裸費用流。
建邊:對於,需要向連,並且向連。費用即爲,流量無窮大。而源點向左側每個點連邊,費用爲0,流量爲,右側向匯點也如此。可以發現,這樣相當於是每一種數的個數翻了一倍,所以最後答案除以2即可。
費用流就是每次按照費用找到一條最短路然後增廣。
那麼如果當前增廣後的費用小於了0,那麼就不流滿,增加流量至費用剛好大等於0。否則可以全部流滿。由於總費用是和0作比較,那麼就不存在除以2的問題。
#include<bits/stdc++.h>
#define cs const
#define re register
#define ll long long
cs int N=205,M=162000,oo=1e9;
cs ll OO=1e18;
int n,key[N],num[N],S,T;ll val[N];
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch=gc();T x=0;int f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
return x*f;
}
inline int gi(){return get<int>();}
inline ll gl(){return get<ll>();}
}
using IO::gi;
using IO::gl;
namespace math{
cs int N=32000;
int mark[N],P[N],cnt=0;
inline void linear_sieves(){
mark[0]=mark[1]=1;
for(int re i=2;i<N;++i){
if(!mark[i]) P[++cnt]=i;
for(int re j=1;j<=cnt&&i*P[j]<N;++j){
mark[i*P[j]]=1;if(i%P[j]==0) break;
}
}
}
inline bool isprime(int x){
if(x<N) return !mark[x];
for(int re j=1,up=sqrt(x);j<=cnt&&P[j]<=up;++j)
if(x%P[j]==0) return false;
return true;
}
}
using math::isprime;
inline void Min(int &x,int y){if(x>y)x=y;}
namespace FLOW{
cs int gN=::N<<1|1;
int Head[gN],Next[M],V[M],W[M],cnt=1;ll C[M];
int edge[gN],pre[gN],flow[gN],vis[gN];ll dis[gN];
//w流量,c費用
inline void add(int u,int v,int w,ll c){Next[++cnt]=Head[u],V[cnt]=v,W[cnt]=w,C[cnt]=c,Head[u]=cnt;}
inline bool SPFA(){
std::queue<int> Q;
for(int re i=1;i<=T;++i) flow[i]=oo,dis[i]=-OO;
dis[S]=0,vis[S]=1,Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop(),vis[u]=0;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]]){
if(W[i]&&dis[v]<dis[u]+C[i]){
dis[v]=dis[u]+C[i],edge[v]=i,pre[v]=u;
Min(flow[v],flow[u]),Min(flow[v],W[i]);
if(!vis[v]) Q.push(v),vis[v]=1;
}
}
}return dis[T]!=-OO;
}
inline int mcf(int ans_flow=0,ll ans_cost=0){
while(SPFA()){
if(ans_cost+dis[T]*flow[T]<0){
ans_flow+=ans_cost/(-dis[T]);break;
}ans_flow+=flow[T],ans_cost+=dis[T]*flow[T];
for(int re u=T;u!=S;u=pre[u])
W[edge[u]]-=flow[T],W[edge[u]^1]+=flow[T];
}return ans_flow/2;
}
}
using FLOW::add;
int main(){
// freopen("2560.in","r",stdin);
n=gi(),S=n<<1|1,T=S+1,math::linear_sieves();
for(int re i=1;i<=n;++i) key[i]=gi();
for(int re i=1;i<=n;++i) num[i]=gi();
for(int re i=1;i<=n;++i) val[i]=gl();
for(int re i=1;i<=n;++i)
for(int re j=1;j<=n;++j)
if(key[i]%key[j]==0&&isprime(key[i]/key[j]))
add(i,j+n,oo,val[i]*val[j]),
add(j+n,i,0,-val[i]*val[j]),
add(j,i+n,oo,val[i]*val[j]),
add(i+n,j,0,-val[i]*val[j]);
for(int re i=1;i<=n;++i) add(S,i,num[i],0),add(i,S,0,0);
for(int re i=1;i<=n;++i) add(i+n,T,num[i],0),add(T,i+n,0,0);
printf("%d \n",FLOW::mcf());
}