很经典的异或问题,对于这种异或计数问题,通常的思想是把它放到一棵二进制树中去看,二进制树中的第 i 层,对应的是一个数中的从高往低数第 i 位的取值,我们需要从根节点开始向下递归去确定取值。
对于一棵二进制树(它可能是原树的一颗子树),如果它的左右孩子是完全一样的,意味着当前位取0或者1都是可以的不影响结果,我们就将ans*=2;
如果不是完全一样的,说明在这一位上必须有所区分,要么取0要么取1,那么,如果在左孩子里出现了右孩子里出现的数,那就不行了,因为当前位只能有一个取值,不能既可以0又可以1.
二进制树在解决异或问题中非常常见,本质是从最高位一位一位的计数!包括位运算计数问题,也可能会用到二进制树的方法!
1 #include "bits/stdc++.h" 2 using namespace std; 3 typedef long long LL; 4 const int MAX=7e4; 5 const LL MOD=1e9+7; 6 LL n,m,a[MAX],ans; 7 bool flag; 8 bitset <MAX> bs; 9 void dfs(int lft,int now){ 10 if (now==0) return; 11 LL len=1<<(now-1); 12 bool ck=true;int i,j; 13 for (i=1;i<=len;i++) 14 if (a[lft+i-1]!=a[lft+len+i-1]) 15 ck=false; 16 if (ck){ 17 ans=ans*2%MOD; 18 dfs(lft,now-1); 19 } 20 else{ 21 bs.reset(); 22 for(i=1;i<=len;i++) bs[a[lft+i-1]]=true; 23 for(i=1;i<=len;i++) 24 if (bs[a[lft+len+i-1]]){ 25 flag=false; 26 return; 27 } 28 dfs(lft,now-1); 29 dfs(lft+len,now-1); 30 } 31 } 32 int main(){ 33 int i,j; 34 scanf("%lld%lld",&n,&m); 35 for (i=1;i<=(1<<n);i++) 36 scanf("%lld",a+i); 37 flag=true; ans=1; 38 dfs(1,n); 39 if (flag) printf("%lld",ans); 40 else printf("0"); 41 return 0; 42 }