分析
我们考虑对所有a[i]质因数分解,然后记cnt[i]为a[i]是由几个质数相乘得到的
然后我们建一个二分图,左面为所有cnt[i]为奇数的点,右面是为偶数的点
我们从源点向左面点连容量b[i]花费0的边,从右面点向汇点连容量b[i]花费0的边
然后两排点之间符合条件的点对连容量inf花费c[i]*c[j]的边
然后跑总花费不小于0的最大费用最大流即可
代码
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<queue> #include<ctime> #include<vector> #include<set> #include<map> #include<stack> using namespace std; #define int long long const int inf = 1e15+7; int n,a[500],b[500],C[500],cnt[500]; int x[500],y[500],l1,l2,s,t,Ans,now,sum; int head[300100],w[300100],c[300100],nxt[300100],to[300100]; int fm[300100],ano[300100],S; inline void add(int x,int y,int z,int cost){ nxt[++S]=head[x];head[x]=S;to[S]=y;w[S]=z;c[S]=cost;fm[S]=x; nxt[++S]=head[y];head[y]=S;to[S]=x;w[S]=0;c[S]=-cost;fm[S]=y; ano[S]=S-1;ano[S-1]=S; } inline int work(int x){ int i,j,k=0; for(i=2;i<=sqrt(x);i++) while(x%i==0)x/=i,k++; if(x>1)k++; return k; } queue<int>q; int iq[100100],nf[100100],la[100100],d[100100]; inline void go(){ int i,j,k; la[s]=0; while(1){ for(i=1;i<=t;i++)d[i]=-inf; q.push(s); d[s]=0,nf[s]=inf,iq[s]=1; while(!q.empty()){ int u=q.front(); q.pop(),iq[u]=0; for(i=head[u];i;i=nxt[i]) if(w[i]&&d[to[i]]<d[u]+c[i]){ d[to[i]]=d[u]+c[i]; la[to[i]]=i; nf[to[i]]=min(w[i],nf[u]); if(!iq[to[i]]){ q.push(to[i]); iq[to[i]]=1; } } } int be=now,ans=Ans,i=la[t]; if(!nf[t]||d[t]==-inf)return; while(i){ w[i]-=nf[t]; w[ano[i]]+=nf[t]; now+=nf[t]*c[i]; i=la[fm[i]]; } Ans+=nf[t]; if(now<0){ Ans=ans+be/abs(d[t]); return; } } } signed main(){ int i,j,k; scanf("%lld",&n); s=n+1,t=n+2; for(i=1;i<=n;i++)scanf("%lld",&a[i]),cnt[i]=work(a[i]); for(i=1;i<=n;i++)scanf("%lld",&b[i]); for(i=1;i<=n;i++)scanf("%lld",&C[i]); for(i=1;i<=n;i++)if(cnt[i]&1) for(j=1;j<=n;j++) if((cnt[i]==cnt[j]+1&&a[i]%a[j]==0) ||(cnt[j]==cnt[i]+1&&a[j]%a[i]==0))add(i,j,inf,C[i]*C[j]); for(i=1;i<=n;i++) if(cnt[i]&1)add(s,i,b[i],0); else add(i,t,b[i],0); go(); printf("%lld\n",Ans); return 0; }