CodeForces 987 F AND Graph
题意:给你一个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 #include<bits/stdc++.h> 2 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<<1 10 #define rson m+1,r,rt<<1|1 11 #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<int,int> 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<<n) - 1; 29 for(int i = 1; i <= m; i++){ 30 scanf("%d", &t); 31 vis[t] = 1; 32 } 33 for(int i = 0; i <= Max; i++){ 34 vis1[i] |= vis[i]; 35 if(vis1[i]) { 36 for(int j = 0; j < n; j++) 37 vis1[i|(1<<j)] = 1; 38 } 39 } 40 bool f = 0; 41 for(int i = 0; i <= Max; i++) pre[i] = i; 42 for(int i = Max; i >= 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<<j)) continue; 50 to = i|(1<<j); 51 if(pre[to] != -1){ 52 u = Find(i); 53 v = Find(to); 54 pre[u] = v; 55 f = 1; 56 } 57 } 58 if(!f){ 59 to = Max ^ i; 60 if(vis1[to]) { 61 u = Find(i); 62 v = Find(to); 63 pre[u] = v; 64 } 65 else pre[i] = -1; 66 } 67 } 68 int ans = 0; 69 for(int i = 0; i <= Max; i++){ 70 if(vis[i] && pre[i] == -1) ans++; 71 if(pre[i] == i) ans++; 72 } 73 printf("%d\n", ans); 74 return 0; 75 }