4514: [Sdoi2016]数字配对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 730 Solved: 311
[ 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
Source
费用流的应用
对于所有数字,可以分为两类,分解质因数后指数和为奇数和偶数。配对关系也只能在两类之间,于是就构成一个二分图的模型。建图之后跑费用流就可以了。
这里还有一个限制,费用总和不小于0,也就是每一步要让费用尽可能大。所以我们将所有费用取反,然后每次SPFA后判断是否会使费用大于0,这样就可以保证了费用的限制。
注意程序第81行的ans-=(cost/dis[t])。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 210
#define maxm 30000
#define inf 1000000000000000000ll
using namespace std;
int n,s,t,cnt=1,tot,totx,toty,ans;
int a[maxn],b[maxn],head[maxn],p[maxn],pri[32005],fx[maxn],fy[maxn];
ll c[maxn],dis[maxn];
bool inq[maxn],vst[32005];
struct edge_type{int next,from,to,v;ll c;}e[maxm];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline bool judge(int x,int y)
{
if (!x||!y) return false;
if (x<y) swap(x,y);
if (x%y!=0) return false;
x/=y;
F(i,1,tot)
{
if (pri[i]>=x) break;
if (x%pri[i]==0) return false;
}
return true;
}
inline void add_edge(int x,int y,int v,ll c)
{
e[++cnt]=(edge_type){head[x],x,y,v,-c};head[x]=cnt;
e[++cnt]=(edge_type){head[y],y,x,0,c};head[y]=cnt;
}
inline bool spfa()
{
queue<int> q;
memset(inq,false,sizeof(inq));
F(i,1,t) dis[i]=inf;
dis[s]=0;inq[s]=true;q.push(s);
while (!q.empty())
{
int x=q.front();q.pop();inq[x]=false;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (e[i].v&&dis[y]>dis[x]+e[i].c)
{
dis[y]=dis[x]+e[i].c;
p[y]=i;
if (!inq[y]) q.push(y),inq[y]=true;
}
}
}
return dis[t]!=inf;
}
inline void mcf()
{
ll cost=0;
while (spfa())
{
int tmp=1000000000;
for(int i=p[t];i;i=p[e[i].from]) tmp=min(tmp,e[i].v);
if (cost+dis[t]*tmp<=0)
{
cost+=dis[t]*tmp;ans+=tmp;
for(int i=p[t];i;i=p[e[i].from]) e[i].v-=tmp,e[i^1].v+=tmp;
}
else
{
ans-=(cost/dis[t]);
return;
}
}
}
int main()
{
n=read();
s=n+1;t=n+2;
F(i,1,n) a[i]=read();
F(i,1,n) b[i]=read();
F(i,1,n) c[i]=read();
F(i,2,32000)
{
if (!vst[i]) pri[++tot]=i;
F(j,1,tot)
{
if (i*pri[j]>32000) break;
vst[i*pri[j]]=true;
if (i%pri[j]==0) break;
}
}
F(i,1,n)
{
int tmp=a[i],num=0;
F(j,1,tot)
{
while (tmp%pri[j]==0) tmp/=pri[j],num++;
if (tmp==1) break;
}
if (num&1) fx[++totx]=i;
else fy[++toty]=i;
}
F(i,1,totx) F(j,1,toty) if (judge(a[fx[i]],a[fy[j]])) add_edge(fx[i],fy[j],1000000000,c[fx[i]]*c[fy[j]]);
F(i,1,totx) add_edge(s,fx[i],b[fx[i]],0);
F(i,1,toty) add_edge(fy[i],t,b[fy[i]],0);
mcf();
printf("%d\n",ans);
}