【BZOJ4514】【SDOI2016】数字配对 [费用流]
数字配对
Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
Input
第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。
Output
一行一个数,最多进行多少次配对
Sample Input
3
2 4 8
2 200 7
-1 -2 1
2 4 8
2 200 7
-1 -2 1
Sample Output
4
HINT
n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5
Solution
显然是一个费用流,并且这可以是一个二分图,由于 ai/aj 要是质数,那显然可以根据质因子个数的奇偶分类。
然后跑一跑最大费用最大流。判断一下值要>=0即可统计入答案。mmpBearChild查了一个下午错,发现是INF开小了qaq。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 #include<map> 9 using namespace std; 10 typedef long long s64; 11 #define next nxt 12 const int N = 1005; 13 const int M = 400005; 14 const int INF = 2147483640; 15 16 int n; 17 int a[N], b[N], c[N]; 18 s64 dist[N]; 19 int vis[N], q[N], pre[N]; 20 int first[M], go[M], next[M], pas[M], from[M], tot; 21 int pNum[M]; 22 int odd[M],Onum, eve[M],Enum; 23 int S, T, Ans; 24 int prime[M], isp[M], p; 25 s64 Val, w[M]; 26 27 int get() 28 { 29 int res=1,Q=1;char c; 30 while( (c=getchar())<48 || c>57 ) 31 if(c=='-')Q=-1; 32 res=c-48; 33 while( (c=getchar())>=48 && c<=57 ) 34 res=res*10+c-48; 35 return res*Q; 36 } 37 38 void Getp(int MaxN) 39 { 40 for(int i=2; i <= MaxN; i++) 41 { 42 if(!isp[i]) prime[++p] = i; 43 for(int j=1; j <= prime[p] && i*prime[j] <= MaxN; j++) 44 { 45 isp[i * prime[j]] = 1; 46 if(i % prime[j] == 0) break; 47 } 48 } 49 } 50 51 int Factor(int x) 52 { 53 int res = 0; 54 while(x != 1) 55 { 56 for(int i=1; i<=p; i++) 57 if(x % prime[i] == 0) 58 { 59 x /= prime[i]; 60 res++; 61 break; 62 } 63 } 64 return res; 65 } 66 67 int PD(int x, int y) 68 { 69 if(x > y) swap(x, y); 70 if(x==0 || y==0 || y%x!=0) return 0; 71 x = y / x; 72 for(int i=2; i<x; i++) 73 if(x % i == 0) return 0; 74 return 1; 75 } 76 77 void Add(int u, int v, int flow, s64 z) 78 { 79 next[++tot]=first[u]; first[u]=tot; go[tot]=v; pas[tot]=flow; w[tot]=z; from[tot]=u; 80 next[++tot]=first[v]; first[v]=tot; go[tot]=u; pas[tot]=0; w[tot]=-z; from[tot]=v; 81 } 82 83 bool Bfs() 84 { 85 for(int i=S; i<=T; i++) dist[i] = -1e18; 86 int tou = 0, wei = 1; 87 q[1] = S; vis[S] = 1; dist[S] = 0; 88 while(tou < wei) 89 { 90 int u = q[++tou]; 91 for(int e=first[u]; e; e=next[e]) 92 { 93 int v=go[e]; 94 if(dist[v] < dist[u] + w[e] && pas[e]) 95 { 96 dist[v] = dist[u] + w[e]; 97 pre[v] = e; 98 if(!vis[v]) 99 { 100 q[++wei] = v; 101 vis[v] = 1; 102 } 103 } 104 } 105 vis[u] = 0; 106 } 107 return dist[T] != -1e18; 108 } 109 110 void Deal() 111 { 112 int x = INF; 113 for(int e=pre[T]; e; e=pre[from[e]]) x = min(x, pas[e]); 114 if(Val + dist[T] * x >= 0) 115 { 116 for(int e=pre[T]; e; e=pre[from[e]]) 117 { 118 pas[e] -= x; 119 pas[((e-1)^1)+1] += x; 120 } 121 Val += dist[T] * x; 122 Ans += x; 123 return; 124 } 125 printf("%lld", Ans - Val / dist[T]); 126 exit(0); 127 } 128 129 int main() 130 { 131 Getp(M - 5); 132 n = get(); 133 for(int i=1; i<=n; i++) a[i] = get(), pNum[i] = Factor(a[i]); 134 for(int i=1; i<=n; i++) b[i] = get(); 135 for(int i=1; i<=n; i++) c[i] = get(); 136 137 S = 0; T = n+1; 138 for(int i=1; i<=n; i++) 139 { 140 if(pNum[i] & 1) Add(S,i, b[i],0), odd[++Onum] = i; 141 else Add(i,T, b[i],0), eve[++Enum] = i; 142 } 143 144 for(int i=1; i<=Onum; i++) 145 for(int j=1; j<=Enum; j++) 146 { 147 int x = odd[i], y = eve[j]; 148 if( PD(a[x], a[y]) ) 149 Add(x,y, INF,(s64)c[x]*c[y]); 150 } 151 152 while(Bfs()) Deal(); 153 printf("%lld", Ans - Val / dist[T]); 154 }
- 视图代码