CodeForces 987 F AND Graph

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)的父亲。

然后如果一个点可以和父亲链接的话, 他的父节点就一定要先连上别的数,如果说他不能连父亲,就找一下max^i 是否可以链接,如果可以链接就链接起来,否则就将这个节点标记为-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 }
CF 987 F

猜你喜欢

转载自www.cnblogs.com/MingSD/p/9113787.html