《游戏英雄升级潜力评估》
题面
问题理解
题目要求我们找出有多少个英雄有潜力通过历练达到2000000000000000级。历练的规则是:如果两个英雄的等级相同,则他们的等级都不会改变;如果英雄等级不同,那么等级较高的英雄会增加1级,而等级较低的英雄则保持不变。
解题思路
- 排序:首先,我们需要对英雄的等级进行排序。排序的目的是为了更容易地处理相同等级的英雄。
- 去重:在排序之后,我们可以通过遍历数组来去除重复的等级。因为如果两个英雄的等级相同,他们无法通过历练来提升等级。
- 计算潜力英雄:在去重之后,剩下的英雄就是有潜力通过历练提升等级的英雄。
具体实现
int solution(int n, std::vector<int> u) {
// write code here
sort(u.begin(), u.end());
int ret = n-1;
for(int i=1;i<n && u[i] == u[i-1];i++){
ret--;
}
return ret;
}
《牛妹的k次奇怪操作》
题面
问题理解
题目要求我们对一个序列进行最多 k
次操作,每次操作可以将序列中的某个元素的二进制表示下最低位的 1
变成 0
。目标是使得操作后的序列总和最小。
解题思路
-
动态规划思想:
- 我们可以使用动态规划来解决这个问题。定义
f0[j]
表示在前i-1
个元素中,使用j
次操作后得到的最小总和。 f1[j]
表示在前i
个元素中,使用j
次操作后得到的最小总和。
- 我们可以使用动态规划来解决这个问题。定义
-
状态转移:
- 对于每个元素
a[i]
,我们需要考虑如何使用操作来减少它的值。 - 我们可以通过逐位检查
a[i]
的二进制表示,找到最低位的1
,并将其变为0
,同时记录操作次数。 - 对于每个可能的操作次数
totalk
,更新f1[totalk]
的值。
- 对于每个元素
-
初始化与更新:
- 初始时,
f0[j]
和f1[j]
都设置为INT_MAX
,表示初始状态下无法达到这些状态。 - 对于每个元素
a[i]
,我们逐位检查并更新f1[totalk]
。 - 最后,将
f1
的值复制到f0
,并重置f1
为INT_MAX
,以便处理下一个元素。
- 初始时,
-
最终结果:
- 在处理完所有元素后,
f0[j]
中存储了使用j
次操作后的最小总和。 - 最终结果是
f0[j]
中的最小值。
- 在处理完所有元素后,
具体实现
int solution(int n, int k, vector<int>& a) {
// 初始化最小总和为 INT_MAX
int minSum = INT_MAX;
// f0[j] 表示在前 i-1 个元素中,使用 j 次操作后得到的最小总和
// f1[j] 表示在前 i 个元素中,使用 j 次操作后得到的最小总和
vector<int> f0(k + 1, 0);
vector<int> f1(k + 1, INT_MAX);
// 遍历每个元素
for (int currentElement : a) {
// 初始化当前元素的操作次数和减去的值
int subtractedValue = 0;
int operationCount = 0;
int currentBit = 1;
// 更新 f1 数组
for (int totalOperations = 0; totalOperations <= k; totalOperations++) {
f1[totalOperations] = min(f1[totalOperations], f0[totalOperations] + currentElement);
}
// 逐位检查当前元素的二进制表示
while (subtractedValue < currentElement) {
// 如果当前位是 1,则可以进行操作
if (currentBit & currentElement) {
subtractedValue += currentBit;
operationCount++;
// 更新 f1 数组,考虑当前操作次数
for (int totalOperations = operationCount; totalOperations <= k; totalOperations++) {
f1[totalOperations] = min(f1[totalOperations], f0[totalOperations - operationCount] + currentElement - subtractedValue);
}
}
// 检查下一位
currentBit <<= 1;
}
// 将 f1 的值复制到 f0,并重置 f1
for (int j = 0; j <= k; j++) {
f0[j] = f1[j];
f1[j] = INT_MAX;
}
}
// 找到使用最多 k 次操作后的最小总和
for (int j = 0; j <= k; j++) {
minSum = min(minSum, f0[j]);
}
return minSum;
}