1 条题解

  • 0
    @ 2025-6-28 15:12:16
    题意:

    给定一个a,一个b,求出所有c的个数使得c小于等于b且a&c=c。

    题解:

    这道题有一个与运算,我们很容易想到应该用二进制表示a和b。

    那么先考虑条件cbc \leq b,那么什么情况下c会小于等于b。考虑两个01字符串表示二进制数,例如00110001001100010010100100101001,我们很容易发现,从左往右数c和b第一个不同的位决定了谁更大。如果在该不同位,b为1,c为0,那么接下来的位不管是什么,c都永远小于b。

    那再考虑条件aa&cc=cc,实际上就是在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
    上传者