有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
我们来考虑配对条件:
如果记f(x)表示x分解质因数后的项数(注意4=2*2所以f(4)=2,也就是说这里指的是分成若干项每一项均为质数的项数)
那么x和y可以配对的条件:f(x)=f(y)+1且x是y的倍数。
易证。
那么如果可以配对进行连边的。
我们把f值为奇数的放一边,f值为偶数的放一边,出来的是二分图!
源向i/i向汇连容量为bi费用为0的边。
i、j可以匹配,i向j连容量为无穷费用为ci*cj的边。
接下来,我们来描述任务:
分配流量使得每条边的流量不大于容量,且获得的费用和不小于0,求最大流。
我们来贪心!
每次沿着费用最长路增广。
如果当前源与汇不连通或者即使往最长路增广1的流量都会使总费用小于0就退出。
假设当前最长路为t,可以增广l的流量。
如果该增广路费用和为负数,那么需要注意保证总费用小于0,详见代码。
然后增广就是了。
(第一次用spfa写费用流
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<deque>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll maxn=200+10,maxm=50000+10,maxd=1000000000,maxdd=1000000,inf=100000000000000000;
ll h[maxn],go[maxm*2],dis[maxm*2],cost[maxm*2],fx[maxm*2],next[maxm*2];
ll a[maxn],b[maxn],c[maxn],col[maxn];
ll d[maxn],rl[maxn],pre[maxn];
deque<ll> dl;
ll pri[maxdd];
bool bz[maxdd];
ll i,j,k,l,r,s,t,n,m,tot,top,ans,now;
void add(ll x,ll y,ll z,ll c,ll d){
go[++tot]=y;
dis[tot]=z;
cost[tot]=c;
fx[tot]=tot+d;
next[tot]=h[x];
h[x]=tot;
}
void spfa(){
fo(i,s,t) d[i]=-inf;
fo(i,s,t) bz[i]=0;
d[s]=0;
rl[s]=inf;
dl.push_back(s);
bz[s]=1;
while (!dl.empty()){
j=dl.front();
r=h[j];
while (r){
if (dis[r]&&d[j]+cost[r]>d[go[r]]){
d[go[r]]=d[j]+cost[r];
pre[go[r]]=r;
rl[go[r]]=min(rl[j],dis[r]);
if (!bz[go[r]]){
bz[go[r]]=1;
dl.push_back(go[r]);
}
}
r=next[r];
}
dl.pop_front();
bz[j]=0;
}
}
int main(){
freopen("pair.in","r",stdin);freopen("pair.out","w",stdout);
fo(i,2,floor(sqrt(maxd))){
if (!bz[i]) pri[++top]=i;
fo(j,1,top){
if (i*pri[j]>floor(sqrt(maxd))) break;
bz[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
scanf("%lld",&n);
fo(i,1,n){
scanf("%lld",&a[i]);
k=a[i];
t=0;
fo(j,1,top)
while (k%pri[j]==0){
t++;
k/=pri[j];
}
col[i]=t;
}
fo(i,1,n) scanf("%lld",&b[i]);
fo(i,1,n) scanf("%lld",&c[i]);
fo(i,1,n)
if (col[i]%2)
fo(j,1,n)
if (col[j]==col[i]-1&&a[i]%a[j]==0||col[j]==col[i]+1&&a[j]%a[i]==0){
add(i+1,j+1,inf,c[i]*c[j],1);
add(j+1,i+1,0,-c[i]*c[j],-1);
}
s=1;t=n+2;
fo(i,1,n){
if (col[i]%2){
add(s,i+1,b[i],0,1);
add(i+1,s,0,0,-1);
}
else{
add(i+1,t,b[i],0,1);
add(t,i+1,0,0,-1);
}
}
while (1){
spfa();
if (d[t]==-inf||now+d[t]<0) break;
if (d[t]>=0) l=rl[t];else l=min(rl[t],now/(-d[t]));
ans+=l;
now+=d[t]*l;
j=t;
while (j!=s){
dis[pre[j]]-=l;
dis[fx[pre[j]]]+=l;
j=go[fx[pre[j]]];
}
}
printf("%lld\n",ans);
}