4205: 卡牌配对 最大流+建图技巧

很明显该题应该是二分图最大匹配,但该题不可能N^2建图,那么我们要怎么办呢?而且有三个属性。 注意到 Ai <= 200 而且 200 以内的质数只有49个,那么我们就可以对着仅有的49个质数下毒手了。很明显如果 Ai 与 Aj 不互质的话, 两者应该有一个共同质因子。 B和C同理。 那么我们可以在S集和T集中间建3层质因子的墙,分别为A和B, B和C, C和A。 只有当 Ai 被第 x 个质因子整除, Bi 被第 y 个质因子整除时, 我们从 i 往 P[0][x][y] 连边。 其他同理。 这样的话每个点连出的边数不超过30. 可以跑了。

  1 #include<cstdio>
  2 #include<iostream>
  3 #define rep(i,j,k) for(register int i = j; i <= k; i++)
  4 #define ez(i,j) for(register int i = head[j]; i; i=e[i].next)
  5 #define maxn 30005
  6 #define maxm 70233
  7 #define inf 0x7fffffff
  8 using namespace std;
  9   
 10 inline int read() {
 11     int s = 0, t = 1; char c = getchar();
 12     while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); }
 13     while( isdigit(c) ) s = s * 10 + c - 48, c = getchar();
 14     return s * t;
 15 }
 16   
 17 struct edge{ int to, v, next; } e[maxm*500]; 
 18 int head[maxm], S = 0, T, cnt = 1;
 19 inline void add(int x,int y,int v) {
 20     e[++cnt].to = y, e[cnt].v = v, e[cnt].next = head[x], head[x] = cnt;
 21     e[++cnt].to = x, e[cnt].v = 0, e[cnt].next = head[y], head[y] = cnt;
 22 }
 23   
 24 int l, r, h[maxm], q[maxm];
 25 #define to e[i].to
 26 inline bool bfs() {
 27     rep(i,1,T) h[i] = 0; h[S] = 1;
 28     l = 0, r = 1; q[r] = S; int x;
 29     while( l < r ) {
 30         x = q[++l]; 
 31         ez(i,x) if( !h[to] && e[i].v ) h[to] = h[x] + 1, q[++r] = to;
 32     } 
 33     return h[T];
 34 }
 35   
 36 inline int dfs(int x,int f) {
 37     if( x == T ) return f;
 38     int used = 0, w;
 39     ez(i,x) if( h[to] == h[x] + 1 && e[i].v ) {
 40         w = dfs(to,min(e[i].v,f-used));
 41         e[i].v -= w, e[i^1].v += w; used += w;
 42         if( used == f ) return f;
 43     }
 44     if( !used ) h[x] = -1;
 45     return used;
 46 }
 47   
 48 int A[maxn], B[maxn], C[maxn], n, m, ans = 0;
 49 int pri[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199};
 50 int bet[3][49][49], inl[maxn], inr[maxn], aq[maxn], bq[maxn], cq[maxn];
 51   
 52 inline void flow() { while( bfs() ) ans += dfs(S,inf); }
 53 int main() {
 54     int n = read(), m = read(), l1, l2, l3, x, tot = 0;
 55     rep(i,0,2) rep(j,0,48) rep(k,0,48) bet[i][j][k] = ++tot;
 56     rep(i,1,n) inl[i] = ++tot; rep(i,1,m) inr[i] = ++tot;
 57     S = 0, T = ++tot;
 58     rep(i,1,n) A[i] = read(), B[i] = read(), C[i] = read();
 59     rep(k,1,n) {
 60         add(S,inl[k],1);
 61         l1 = 0, l2 = 0, l3 = 0; 
 62         x = A[k];
 63         rep(i,0,48) if( x % pri[i] == 0 ) {
 64                 aq[++l1] = i;
 65                 while( x % pri[i] == 0 ) x /= pri[i];
 66         } else if( x == 1 ) break;
 67         x = B[k];
 68         rep(i,0,48) if( x % pri[i] == 0 ) {
 69                 bq[++l2] = i;
 70                 while( x % pri[i] == 0 ) x /= pri[i];
 71         } else if( x == 1 ) break;
 72         x = C[k];
 73         rep(i,0,48) if( x % pri[i] == 0 ) {
 74                 cq[++l3] = i;
 75                 while( x % pri[i] == 0 ) x /= pri[i]; 
 76         } else if( x == 1 ) break;
 77         rep(i,1,l1) rep(j,1,l2) add(inl[k],bet[0][aq[i]][bq[j]],1);
 78         rep(i,1,l2) rep(j,1,l3) add(inl[k],bet[1][bq[i]][cq[j]],1);
 79         rep(i,1,l3) rep(j,1,l1) add(inl[k],bet[2][cq[i]][aq[j]],1);
 80     }   
 81     rep(i,1,m) A[i] = read(), B[i] = read(), C[i] = read();
 82     rep(k,1,m) {
 83         add(inr[k],T,1);
 84         l1 = 0, l2 = 0, l3 = 0; 
 85         x = A[k];
 86         rep(i,0,48) if( x % pri[i] == 0 ) {
 87                 aq[++l1] = i;
 88                 while( x % pri[i] == 0 ) x /= pri[i];
 89         } else if( x == 1 ) break;
 90         x = B[k];
 91         rep(i,0,48) if( x % pri[i] == 0 ) {
 92                 bq[++l2] = i;
 93                 while( x % pri[i] == 0 ) x /= pri[i];
 94         } else if( x == 1 ) break;
 95         x = C[k];
 96         rep(i,0,48) if( x % pri[i] == 0 ) {
 97                 cq[++l3] = i;
 98                 while( x % pri[i] == 0 ) x /= pri[i]; 
 99         } else if( x == 1 ) break; 
100         rep(i,1,l1) rep(j,1,l2) add(bet[0][aq[i]][bq[j]],inr[k],1);
101         rep(i,1,l2) rep(j,1,l3) add(bet[1][bq[i]][cq[j]],inr[k],1);
102         rep(i,1,l3) rep(j,1,l1) add(bet[2][cq[i]][aq[j]],inr[k],1);
103     }
104     flow();
105     printf("%d\n", ans);
106     return 0;
107  }

 

人一我十,人十我万!追逐青春的梦想,怀着自信的心,永不放弃!仿佛已看到希望,尽管还在远方

posted on 2016-05-05 21:23  83131  阅读(196)  评论(0编辑  收藏  举报

导航