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 "); 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 ",ans); } }