CF1557 C. Moamen and XOR

https://codeforces.com/problemset/problem/1557/C

 

题意:

 构造n个小于2^k的数,满足他们按位与的结果>=按位异或的结果

 

位运算只需要关心每一位的整体情况即可,不必要给关系n个数具体是什么

从高位往低位枚举(k-1 到 0)

设f[i]表示前i位按位与=按位异或的答案

枚举是从第i位开始按位与>按位异或的,同时累计第i位就决出大小关系的答案(因为第i位决出大小关系之后,后面的位可以任意填)

分2种情况

1、按位与这一位是1,那么要求n个数这一位都是1。

如果n是奇数,那么到目前依然按位与=按位异或,所以f[i]=f[i-1]

如果n是偶数,那么按位异或这一位的结果是偶数,到这一位已经决出>=关系是满足了,后面的k-1-i位就可以任意填。1个数有2^(k-1-i)种可能,n个数就是( 2^(k-1-i) )^n。所以f[i]=f[i-1]*( 2^(k-1-i) )^n

2、按位与这一位是0,那么这n个数这一位不全是1

要求按位异或的这一位也必须是0,所以这一位必须是总共有偶数个1。所以是C(n,0)+C(n,2)+C(n,4)+……

如果n是奇数,最后加到C(n,n-1)

如果n是偶数,最后加到C(n,n-2),因为不能所有数这一位都是1

可以利用杨辉三角第i行的和等于2^i,且奇数项的和=偶数项的和。如果n是偶数把C(n,n)=1减去即可

 

#include<bits/stdc++.h>

const int mod=1e9+7;

#define N 200003

int f[N];

int poww(int a,int b)
{
    int c=1;
    for(;b;a=1ll*a*a%mod,b>>=1)
        if(b&1) c=1ll*c*a%mod;
    return c; 
}

int main()
{
    int T,n,k,ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        if(!k)
        {
            printf("1\n");
            continue; 
        }
        ans=0;
        if(n&1) f[0]=1;
        else 
        {
            f[0]=0;
            ans=poww(poww(2,k-1),n);
        }
        f[0]+=poww(2,n-1);
        if(!(n&1)) f[0]--;
        for(int i=1;i<k;++i)
        {
            if(n&1) f[i]=f[i-1];
            else 
            {
                f[i]=0;
                ans=(ans+1ll*f[i-1]*poww(poww(2,k-1-i),n)%mod)%mod;
            }
            f[i]=(f[i]+1ll*f[i-1]*poww(2,n-1)%mod)%mod;
            if(!(n&1)) f[i]=(f[i]-f[i-1]+mod)%mod;
        }
        ans=(ans+f[k-1])%mod;
        printf("%d\n",ans);
    }
}

 

posted @ 2021-09-07 16:21  TRTTG  阅读(45)  评论(0编辑  收藏  举报