题意:给你一个n,一个m,m < 2^n, 然后就是如果 x & y == 0 的话就可以将这2个数连起来, 求最后的有几块。
题解:对于一个数 11000 则 他必定可以 与 00111相链接, 那么也一定可以和00111中间少了任何几个1的数相连。
任何我们对于任意一个数都跑出他的父亲 他的父亲就比他多一个1。
如 00001 他的父亲可以为 10001 01001 00101 00011 这4个, 至于 10101 则是 10001(00101)的父亲。
但是,对于一个数来说,他不能直接和他的父节点链接,必须要父节点先和别的数链接,然后子节点就一定可以和父节点链接的那个数链接。
我们先从小到大跑出所有的可以父节点,开另外一个数组去标记。
然后我们从大的数先开始处理,这样我们就会先访问到祖先节点,再访问到子节点,这样可以保证,我们访问到子节点的时候,他的父节点已经处理过了,我们可以得知这2个点是否可以相连接。
对于处理到每一个点,我们先找他的所有父节点,如果可以链接,就直接链接,如果他不能和父节点链接,就去找他的对立节点(即0->1, 1->0),看看这2个点是否可以链接,可以就相连,不可以就将这个节点标记为-1,即没有链接的节点,从而当该节点的子节点访问的时候,就可以得知不能链接。
然后链接的时候用并查集链接块,最后看有几个联通块就是答案了。
代码:
1 #include2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<110 #define rson m+1,r,rt<<1|111 #define max3(a,b,c) max(a,max(b,c))12 #define min3(a,b,c) min(a,min(b,c))13 #define _S(X) cout << X << ' ';14 #define __S(X) cout << X << endl;15 typedef pair pll;16 const int INF = 0x3f3f3f3f;17 const LL mod = (int)1e9+7;18 const int N = (1<<22) + 100;19 bool vis[N], vis1[N];20 int pre[N];21 int Find(int x){22 if(x == pre[x]) return x;23 return pre[x] = Find(pre[x]);24 }25 int main(){26 int n, m, t, to, u, v;27 scanf("%d%d", &n, &m);28 int Max = (1< = 0; i--){43 if(!vis1[i]){44 pre[i] = -1;45 continue;46 }47 f = 0;48 for(int j = 0; j < n; j++){49 if(i&(1<