Tenka1 Programmer Beginner Contest D IntegerotS(补)

当时没做出来,官方题解没看懂,就看别人提交的代码,刚对着别人代码调了几组数据,才发现,思路差不多,不过,原来是这样实现啊,果然我还是很菜

思路:题目要求是选取的这些数字全部进行OR运算,结果<=k,有点贪心的感觉,想到有些数字OR运算之后结果>k,肯定有一位到多位在结果中是1,但是k中是0,但是怎么选择去掉哪个呢?我是想着计算每个数在每一位的贡献,把小的去掉。但是我不会算。调别人的代码才发现,他采取的策略是通过位运算,依次去掉k的每一位1,并且同时把当前位以下的位全部用1补上,然后寻找符合条件的结果。这样每次枚举都会少1位,每次选取符合条件的结果,取最大的就是结果了。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e5+10;
int a[MAXN];
int b[MAXN];
int n,k;
int fac[31];

void init()
{
    for(int i = 0; i < 31; ++i)
        fac[i] = 1<<i;
}

int main()
{
    init();
    scanf("%d %d",&n,&k);
    long long res = 0;
    for(int i = 0; i < n; ++i)
    {
        scanf("%d %d",&a[i],&b[i]);
        if((a[i]&k)==a[i]) res += b[i];
    }
    for(int i = 30; i >= 0; --i)
    {
        if(k&fac[i])
        {
            int tmp = (k^fac[i])|(fac[i]-1);
            //printf("%d
",tmp);
            long long ans = 0;
            for(int j = 0; j < n; ++j)
                if((a[j]&tmp)==a[j]) ans += b[j];
            res = max(res,ans);
        }
    }
    printf("%lld
",res);
    return 0;
}

原文地址:https://www.cnblogs.com/guoyongheng/p/7617348.html