图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

时间:2023-03-09 16:29:55
图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 820  Solved: 345
[Submit][Status][Discuss]

Description

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

Input

第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。

Output

一行一个数,最多进行多少次配对

Sample Input

3
2 4 8
2 200 7
-1 -2 1

Sample Output

4

HINT

n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

  

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=;
const int maxm=;
long long INF=1000000000000000LL;
int cnt=,fir[maxn],nxt[maxm],to[maxm],ID[maxn],path[maxn],n;
long long a[maxn],b[maxn],c[maxn],cost[maxm],cap[maxm],dis[maxn],val[maxm]; void addedge(int a,int b,long long c,long long v){
nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
} int S,T;
long long Spfa(){
queue<int>q;
q.push(S);
for(int i=S;i<=T;i++)
dis[i]=-INF;dis[S]=;
while(!q.empty()){
int node=q.front();q.pop();
for(int i=fir[node];i;i=nxt[i])
if(cap[i]&&dis[node]+val[i]>dis[to[i]]){
dis[to[i]]=val[i]+dis[node];
path[to[i]]=i;
q.push(to[i]);
}
} return dis[T]==-INF?INF:dis[T];
} long long Aug(){
int p=T;
long long f=INF;
while(p!=S){
f=min(f,cap[path[p]]);
p=to[path[p]^];
}
p=T;
while(p!=S){
cap[path[p]]-=f;
cap[path[p]^]+=f;
p=to[path[p]^];
}
return f;
} long long MCMF(){
long long ret=,now=,c,d;
while((d=Spfa())!=INF){
c=Aug();
if(c*d+now<)
return ret-now/d;
else{ret+=c;now+=c*d;}
}
return ret;
} bool Get_ID(int x){
bool ret=true;
for(int i=,m=(int)sqrt(x);i<=m;i++)
if(x%i==){while(x%i==)x/=i,ret=!ret;}
if(x!=)ret=!ret;
return ret;
} bool IS_Prime(int x){
for(int i=,m=(int)sqrt(x);i<=m;i++)
if(x%i==)return false;
return true;
} int main(){
scanf("%d",&n);S=;T=n+;
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
for(int i=;i<=n;i++)scanf("%lld",&b[i]);
for(int i=;i<=n;i++)scanf("%lld",&c[i]);
for(int i=;i<=n;i++)ID[i]=Get_ID(a[i]);
for(int i=;i<=n;i++){
if(!ID[i]){
addedge(S,i,b[i],);addedge(i,S,,);
for(int j=;j<=n;j++)
if(ID[j]){
long long x=a[i],y=a[j];if(x<y)swap(x,y);
if(x%y==&&IS_Prime(x/y)){
addedge(i,j,INF,c[i]*c[j]);
addedge(j,i,,-c[i]*c[j]);
}
}
}
else{addedge(i,T,b[i],);addedge(T,i,,);}
}
printf("%lld\n",MCMF());
return ;
}