有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
一行一个数,最多进行多少次配对
n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5
鸣谢Menci上传
费用流的应用
对于所有数字,可以分为两类,分解质因数后指数和为奇数和偶数。配对关系也只能在两类之间,于是就构成一个二分图的模型。建图之后跑费用流就可以了。
这里还有一个限制,费用总和不小于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); }