《游戏英雄升级潜力评估》《牛妹的k次奇怪操作》

64 阅读3分钟

《游戏英雄升级潜力评估》

题面

image.png

问题理解

题目要求我们找出有多少个英雄有潜力通过历练达到2000000000000000级。历练的规则是:如果两个英雄的等级相同,则他们的等级都不会改变;如果英雄等级不同,那么等级较高的英雄会增加1级,而等级较低的英雄则保持不变。

解题思路

  1. 排序:首先,我们需要对英雄的等级进行排序。排序的目的是为了更容易地处理相同等级的英雄。
  2. 去重:在排序之后,我们可以通过遍历数组来去除重复的等级。因为如果两个英雄的等级相同,他们无法通过历练来提升等级。
  3. 计算潜力英雄:在去重之后,剩下的英雄就是有潜力通过历练提升等级的英雄。

具体实现

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次奇怪操作》

题面

image.png

问题理解

题目要求我们对一个序列进行最多 k 次操作,每次操作可以将序列中的某个元素的二进制表示下最低位的 1 变成 0。目标是使得操作后的序列总和最小。

解题思路

  1. 动态规划思想

    • 我们可以使用动态规划来解决这个问题。定义 f0[j] 表示在前 i-1 个元素中,使用 j 次操作后得到的最小总和。
    • f1[j] 表示在前 i 个元素中,使用 j 次操作后得到的最小总和。
  2. 状态转移

    • 对于每个元素 a[i],我们需要考虑如何使用操作来减少它的值。
    • 我们可以通过逐位检查 a[i] 的二进制表示,找到最低位的 1,并将其变为 0,同时记录操作次数。
    • 对于每个可能的操作次数 totalk,更新 f1[totalk] 的值。
  3. 初始化与更新

    • 初始时,f0[j]f1[j] 都设置为 INT_MAX,表示初始状态下无法达到这些状态。
    • 对于每个元素 a[i],我们逐位检查并更新 f1[totalk]
    • 最后,将 f1 的值复制到 f0,并重置 f1INT_MAX,以便处理下一个元素。
  4. 最终结果

    • 在处理完所有元素后,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;
}