bzoj4514 [Sdoi2016]数字配对

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

Sample Output

4

HINT

 n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

 

正解:费用流。

这题的费用流模型还是比较显然的,不过有两个要注意的地方。

首先这题需要建成二分图的模型,所以每个点的流量肯定会乘$2$,如果直接连可能会导致有些点多用了流量。对于这种情况,我们在每个$i->j$的连边时,把$j->i$也连边,最后把流量除以$2$,就能解决这个问题了。

还有一个问题,题目是问的费用$>=0$的最大流,首先我们肯定要把费用取反,转成最小费用最大流。然后我们可以在每次增广时加一个特判,如果之前增广的费用+当前费用$>0$,那么我们直接取使得费用$<=0$的最大流量就行了。因为费用流每次都是找最短路增广,所以这样做是对的。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <complex>
 5 #include <cstring>
 6 #include <cstdlib>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cmath>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <set>
14 #define inf (1LL<<60)
15 #define N (3010)
16 #define il inline
17 #define RG register
18 #define ll long long
19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
20 
21 using namespace std;
22 
23 struct edge{ ll nt,to,flow,cap,dis; }g[200010];
24 
25 ll head[N],dis[N],vis[N],f[N],p[N],fa[N],a[N],b[N],c[N];
26 ll q[5000010],n,S,T,flow,cost,num=1;
27 
28 il ll gi(){
29     RG ll x=0,q=1; RG char ch=getchar();
30     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
31     if (ch=='-') q=-1,ch=getchar();
32     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
33     return q*x;
34 }
35 
36 il void insert(RG ll from,RG ll to,RG ll cap,RG ll cost){
37     g[++num]=(edge){head[from],to,0,cap,cost},head[from]=num; return;
38 }
39 
40 il ll bfs(RG ll S,RG ll T){
41     for (RG ll i=1;i<=T;++i) dis[i]=inf;
42     RG ll h=0,t=1; q[t]=S,dis[S]=0,vis[S]=1,f[S]=inf;
43     while (h<t){
44     RG ll x=q[++h],v;
45     for (RG ll i=head[x];i;i=g[i].nt){
46         v=g[i].to;
47         if (dis[v]>dis[x]+g[i].dis && g[i].cap>g[i].flow){
48         dis[v]=dis[x]+g[i].dis,fa[v]=x,p[v]=i;
49         f[v]=min(f[x],g[i].cap-g[i].flow);
50         if (!vis[v]) vis[v]=1,q[++t]=v;
51         }
52     }
53     vis[x]=0;
54     }
55     if (dis[T]==inf) return 0;
56     if (cost+dis[T]*f[T]>0){ //费用>0特判
57     RG ll x=-cost/dis[T];
58     flow+=x; return 0;
59     }
60     flow+=f[T],cost+=dis[T]*f[T];
61     for (RG ll i=T;i!=S;i=fa[i])
62     g[p[i]].flow+=f[T],g[p[i]^1].flow-=f[T];
63     return 1;
64 }
65 
66 il ll isprime(RG ll x){
67     if (x==0 || x==1) return 0;
68     if (!(x&1)) return x==2;
69     for (RG ll i=2;i*i<=x;++i)
70     if (!(x%i)) return 0;
71     return 1;
72 }
73 
74 il void work(){
75     n=gi(),S=2*n+1,T=2*n+2;
76     for (RG ll i=1;i<=n;++i) a[i]=gi();
77     for (RG ll i=1;i<=n;++i) b[i]=gi();
78     for (RG ll i=1;i<=n;++i) c[i]=gi();
79     for (RG ll i=1;i<=n;++i){
80     insert(S,i,b[i],0),insert(i,S,0,0);
81     insert(n+i,T,b[i],0),insert(T,n+i,0,0);
82     }
83     for (RG ll i=1;i<=n;++i)
84     for (RG ll j=1;j<=n;++j){
85         if (a[i]%a[j]) continue;
86         if (isprime(a[i]/a[j])){
87         insert(i,n+j,inf,-c[i]*c[j]),insert(n+j,i,0,c[i]*c[j]);
88         insert(j,n+i,inf,-c[i]*c[j]),insert(n+i,j,0,c[i]*c[j]);
89         //防止多余流量影响结果
90         }
91     }
92     while (bfs(S,T)); printf("%lld\n",flow>>1); return;
93 }
94 
95 int main(){
96     File("match");
97     work();
98     return 0;
99 }

 

posted @ 2017-04-13 09:12  wfj_2048  阅读(244)  评论(0编辑  收藏  举报