1 条题解
-
0
题意:
给定一个a,一个b,求出所有c的个数使得c小于等于b且a&c=c。
题解:
这道题有一个与运算,我们很容易想到应该用二进制表示a和b。
那么先考虑条件,那么什么情况下c会小于等于b。考虑两个01字符串表示二进制数,例如,,我们很容易发现,从左往右数c和b第一个不同的位决定了谁更大。如果在该不同位,b为1,c为0,那么接下来的位不管是什么,c都永远小于b。
那再考虑条件&=,实际上就是在a是0的二进制位上c不能是1,a是1的位上c可以是0也可以是1,也就是说c是a的二进制子集。如果只考虑该条件,那么答案应该就是a+1(因为有全0的存在),或者说是。
那么我们现在将两个条件结合起来。
我们照例先从高位往低位遍历,如果该位b为1,a也为1,那么我们很容易发现,只要c在该位为0,且同时满足c为a的二进制子集即可。我们计剩余没遍历过的a的二进制位中为1的个数为m,那么c在该位为0的符合要求的可能性总数就是2的m次幂。
但此时并没有找到所有符合可能性的c,因为c在该位为1仍然有可能小于等于b,所以接着遍历重复上述操作。
如果遇到某一位a为0,b为1,那么只要c是a的子集,不管c是多少都会小于b,那么在进行上述记录可能性总数的操作后我们就找到了所有可能性。
如果遇到某一位a为1,b为0,我们可以直接忽略掉继续往下遍历,因为这一位c只能为0且无法判断大小关系。
最后如果遍历完所有位都没出现a为0,b为1的情况,那么要给答案加上1,因为此前我们只考虑了c在该位为0的情况,而在跑到最后都没发现a为0,b为1的时候,c在此处取1也符合要求。
写法:
将a和b以二进制表示,从高位往低位找,当该位b为1,加上2的a下面1的个数的次幂。如果b是1,a是0,计算完后break。如果跑到最后一位还没break就加1.
#define int long long int cal(int a,int b){ vector<int> pre(63); vector<int> p2(63); p2[0] = 1; for(int i = 1;i<63;i++) p2[i] = p2[i-1]*2; for(int i = 0;i<63;i++){ pre[i] = (a&p2[i])!=0; if(i>0)pre[i]+=pre[i-1]; } int res = 0; for(int i = 62;i>=0;i--){ if((b&p2[i])!=0){ res+=p2[(i>0?pre[i-1]:0)]; if((a&p2[i])==0) break; } if(i==0) res+=1; } return res; }
- 1
信息
- ID
- 9
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 103
- 已通过
- 9
- 上传者