裸费用流。
建边:对于
a
[
i
]
a
[
j
]
=
p
r
i
m
e
&
a
[
j
]
∣
a
[
i
]
\frac{a[i]}{a[j]}=prime \& a[j]|a[i]
a[j]a[i]=prime&a[j]∣a[i],需要
i
i
i向
j
+
n
j+n
j+n连,并且
j
j
j向
i
+
n
i+n
i+n连。费用即为
c
[
i
]
∗
c
[
j
]
c[i]*c[j]
c[i]∗c[j],流量无穷大。而源点向左侧每个点连边,费用为0,流量为
b
[
i
]
b[i]
b[i],右侧向汇点也如此。可以发现,这样相当于是每一种数的个数翻了一倍,所以最后答案除以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());
}