当前位置:首页 > 比赛题解 > GESP2023年五级题烹饪问题:从暴力枚举到位运算优化深度解析(洛谷P3930)

GESP2023年五级题烹饪问题:从暴力枚举到位运算优化深度解析(洛谷P3930)

1周前 (06-24)比赛题解74

截图未命名.jpg GESP2023年五级题烹饪问题:从暴力枚举到位运算优化深度解析(洛谷P3930) GESP2023 五级考题 烹饪问题 洛谷P3930 位运算优化 按位与运算 贪心算法 算法竞赛 第1张

一、题目分析

我们需要在N种食材中找到两种食材,使得它们美味度的按位与运算结果最大。直接暴力枚举所有组合的时间复杂度是O(N²),对于大数据量会超时。我们需要更高效的算法

二、高效解法思路

我们可以从最高位开始,尝试构建最大的按位与结果。对于每一位,我们检查是否有至少两个数字在该位为1,并且这些数字在前面的高位也满足我们的构建要求。

1. 算法思路

  • 从最高位(第30位)开始逐位检查

  • 尝试构建最大的按位与结果

  • 对于每一位,检查是否有至少两个数字满足当前构建的模式

  • 如果有,保留这一位;否则,跳过这一位

2. 关键点

  • 使用mask来跟踪当前构建的模式

  • 使用temp来尝试设置当前位

  • 统计满足条件的数字数量

3. 复杂度分析

  • 时间复杂度:O(32*N) ≈ O(N),非常高效

  • 空间复杂度:O(1),只使用了常数个额外变量

4. 优化

  • 提前终止:一旦找到两个满足条件的数字就可以停止统计

  • 位运算优化:使用位运算代替乘除法

三、完整代码

#include <iostream>
#include <vector>
using namespACe std;

int findMaxAnd(vector<int>& nums) {
    int mask = 0;
    int max_and = 0;
    
    // 从最高位开始检查
    for (int i = 30; i >= 0; i--) {
        // 尝试设置这一位
        mask |= (1 << i);
        int count = 0;
        int temp = max_and | (1 << i);
        
        // 统计有多少数字包含当前构建的模式
        for (int num : nums) {
            if ((num & mask) == temp) {
                count++;
                if (count >= 2) break;
            }
        }
        
        // 如果有至少两个数字满足,保留这一位
        if (count >= 2) {
            max_and = temp;
        } else {
            mask ^= (1 << i); // 撤销这一位
        }
    }
    
    return max_and;
}

int main() {
    int N;
    cin >> N;
    vector<int> a(N);
    for (int i = 0; i < N; i++) {
        cin >> a[i];
    }
    
    cout << findMaxAnd(a) << endl;
    return 0;
}


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。