【BZOJ4514】【SDOI2016】數字配對 [費用流]
阿新 • • 發佈:2017-06-04
cnblogs out dea clas sin mic ostream 個數字 iostream
[Submit][Status][Discuss]
第三行 n 個整數 b1、b2、……、bn。
第四行 n 個整數 c1、c2、……、cn。
2 4 8
2 200 7
-1 -2 1
數字配對
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。Output
一行一個數,最多進行多少次配對
Sample Input
32 4 8
2 200 7
-1 -2 1
Sample Output
4HINT
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
12 const int ONE = 205*205;
13 const int INF = 2147483640;
14
15 int n;
16 int a[ONE], b[ONE], c[ONE];
17 s64 dist[ONE];
18 int vis[ONE], q[ONE*10], pre[ONE];
19 int first[ONE], go[ONE], next[ONE], pas[ONE], from[ONE], tot;
20 int pNum[ONE];
21 int odd[ONE],Onum, eve[ONE],Enum;
22 int S, T, Ans;
23 int prime[ONE], isp[ONE], p;
24 s64 Val, w[ONE];
25
26 int get()
27 {
28 int res=1,Q=1;char c;
29 while( (c=getchar())<48 || c>57 )
30 if(c==‘-‘)Q=-1;
31 res=c-48;
32 while( (c=getchar())>=48 && c<=57 )
33 res=res*10+c-48;
34 return res*Q;
35 }
36
37 void Getp(int MaxN)
38 {
39 for(int i=2; i <= MaxN; i++)
40 {
41 if(!isp[i]) prime[++p] = i;
42 for(int j=1; j <= prime[p], i*prime[j] <= MaxN; j++)
43 {
44 isp[i * prime[j]] = 1;
45 if(i % prime[j] == 0) break;
46 }
47 }
48 }
49
50 int Factor(int x)
51 {
52 int res = 0;
53 while(x != 1)
54 {
55 for(int i=1; i<=p; i++)
56 if(x % prime[i] == 0)
57 {
58 x /= prime[i];
59 res++;
60 break;
61 }
62 }
63 return res;
64 }
65
66 int PD(int x, int y)
67 {
68 if(x > y) swap(x, y);
69 if(x==0 || y==0 || y%x!=0) return 0;
70 x = y / x;
71 for(int i=2; i<x; i++)
72 if(x % i == 0) return 0;
73 return 1;
74 }
75
76 int Add(int u, int v, int flow, s64 z)
77 {
78 next[++tot]=first[u]; first[u]=tot; go[tot]=v; pas[tot]=flow; w[tot]=z; from[tot]=u;
79 next[++tot]=first[v]; first[v]=tot; go[tot]=u; pas[tot]=0; w[tot]=-z; from[tot]=v;
80 }
81
82 bool Bfs()
83 {
84 for(int i=S; i<=T; i++) dist[i] = -1e18;
85 int tou = 0, wei = 1;
86 q[1] = S; vis[S] = 1; dist[S] = 0;
87 while(tou < wei)
88 {
89 int u = q[++tou];
90 for(int e=first[u]; e; e=next[e])
91 {
92 int v=go[e];
93 if(dist[v] < dist[u] + w[e] && pas[e])
94 {
95 dist[v] = dist[u] + w[e];
96 pre[v] = e;
97 if(!vis[v])
98 {
99 q[++wei] = v;
100 vis[v] = 1;
101 }
102 }
103 }
104 vis[u] = 0;
105 }
106 return dist[T] != -1e18;
107 }
108
109 void Deal()
110 {
111 int x = INF;
112 for(int e=pre[T]; e; e=pre[from[e]]) x = min(x, pas[e]);
113 if(Val + dist[T] * x >= 0)
114 {
115 for(int e=pre[T]; e; e=pre[from[e]])
116 {
117 pas[e] -= x;
118 pas[((e-1)^1)+1] += x;
119 }
120 Val += dist[T] * x;
121 Ans += x;
122 return;
123 }
124 printf("%d", Ans - Val / dist[T]);
125 exit(0);
126 }
127
128 int main()
129 {
130 Getp(ONE);
131 n = get();
132 for(int i=1; i<=n; i++) a[i] = get(), pNum[i] = Factor(a[i]);
133 for(int i=1; i<=n; i++) b[i] = get();
134 for(int i=1; i<=n; i++) c[i] = get();
135
136 S = 0; T = n+1;
137 for(int i=1; i<=n; i++)
138 {
139 if(pNum[i] & 1) Add(S,i, b[i],0), odd[++Onum] = i;
140 else Add(i,T, b[i],0), eve[++Enum] = i;
141 }
142
143 for(int i=1; i<=Onum; i++)
144 for(int j=1; j<=Enum; j++)
145 {
146 int x = odd[i], y = eve[j];
147 if( PD(a[x], a[y]) )
148 Add(x,y, INF,(s64)c[x]*c[y]);
149 }
150
151 while(Bfs()) Deal();
152 printf("%d", Ans - Val / dist[T]);
153 }
View Code
【BZOJ4514】【SDOI2016】數字配對 [費用流]