可惜没如果=_=
时光的河入海流

 

 

 

 

很经典的异或问题,对于这种异或计数问题,通常的思想是把它放到一棵二进制树中去看,二进制树中的第 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 }

 

posted on 2022-07-10 19:56  珍珠鸟  阅读(39)  评论(0)    收藏  举报