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\n",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\n",res);
return 0;
}