http://tenka1-2017.contest.atcoder.jp/tasks/tenka1_2017_d
给定N,K和A1...AN,B1...BN,选取若干个Ai使它们的或运算值小于等于K时,使得对应的ΣBi值最大,求最大值。
其实我不大理解为什么要这么弄。
一个数K,如果X小于它,那么K的二进制中第r位是1,X的第r位可以是0或1;但如果K的第r位是0,X的第r位一定是0。
我只能勉强这样想:
可以先选定一个或运算值的上限tmp,如果(Ai|tmp==tmp),那么根据或运算性质当前这个Ai是肯等可以选的,由于Bi>0,自然能选的越多越好。但是要是一个一个枚举或运算上限显然不现实。所以要按照K的二进制来枚举,把K中位是1的变为0,前面位不变,后面位全变为1。
codeforce上有人这么写:
Let's constder about the pattern of K = 13:
All of buying things are 0 (0 or 1) (0 or 1) (0 or 1) in binary-representation, 0 — 7 in decimal
All of buying things are 1 0 (0 or 1) (0 or 1) in binary-representation, 8 — 11 in decimal
All of buying things are 1 1 0 (0 or 1) in binary-representation, 12 — 13 in decimal
You can choose any pattern to buying, of above patterns.
Let's constder about an another pattern, K = 22:
All of buying things are 0 (0 or 1) (0 or 1) (0 or 1) (0 or 1) in binary-representation, 0 — 15 in decimal
All of buying things are 1 0 0 (0 or 1) (0 or 1) in binary-representation, 16 — 19 in decimal
All of buying things are 1 1 0 0 (0 or 1) in binary-representation, 20 — 21 in decimal
All of buying things are 1 1 0 0 0 in binary-representation, 22 in decimal
You can choose any pattern to buying, of above patterns.
So, you can divide [1, K] into logK parts (maximum). The complexity is N * logK = O(NlogK).
官方题解:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=1e5+100; 6 int a[maxn],b[maxn]; 7 int fac[32]; 8 9 int main() 10 { 11 int N,K; 12 scanf("%d%d",&N,&K); 13 ll res=0; 14 for(int i=0;i<N;i++){ 15 scanf("%d%d",&a[i],&b[i]); 16 if((a[i]|K)==K) res+=b[i]; 17 } 18 for(int i=0;i<=30;i++) 19 fac[i]=1<<i; 20 for(int i=1;i<=30;i++){ 21 if(K&fac[i]){ 22 ll cnt=0; 23 int tmp=(K^fac[i])|(fac[i]-1);//把当前位置为0,前面位不变,后面位全为1 24 for(int j=0;j<N;j++) 25 if((a[j]|tmp)==tmp) cnt+=b[j]; 26 res=max(res,cnt); 27 } 28 } 29 cout<<res<<endl; 30 }