图论(费用流):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

 

  

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <cmath>
  6 using namespace std;
  7 const int maxn=210;
  8 const int maxm=40010;
  9 long long INF=1000000000000000LL;
 10 int cnt=1,fir[maxn],nxt[maxm],to[maxm],ID[maxn],path[maxn],n;
 11 long long a[maxn],b[maxn],c[maxn],cost[maxm],cap[maxm],dis[maxn],val[maxm];
 12 
 13 void addedge(int a,int b,long long c,long long v){
 14     nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
 15 }
 16 
 17 int S,T;
 18 long long Spfa(){
 19     queue<int>q;
 20     q.push(S);
 21     for(int i=S;i<=T;i++)
 22         dis[i]=-INF;dis[S]=0;
 23     while(!q.empty()){
 24         int node=q.front();q.pop();
 25         for(int i=fir[node];i;i=nxt[i])
 26             if(cap[i]&&dis[node]+val[i]>dis[to[i]]){
 27                 dis[to[i]]=val[i]+dis[node];
 28                 path[to[i]]=i;
 29                 q.push(to[i]);
 30             }
 31     }
 32     
 33     return dis[T]==-INF?INF:dis[T]; 
 34 }
 35 
 36 long long Aug(){
 37     int p=T;
 38     long long f=INF;
 39     while(p!=S){
 40         f=min(f,cap[path[p]]);
 41         p=to[path[p]^1];
 42     }
 43     p=T;
 44     while(p!=S){
 45         cap[path[p]]-=f;
 46         cap[path[p]^1]+=f;
 47         p=to[path[p]^1];
 48     }
 49     return f;
 50 }
 51 
 52 long long MCMF(){
 53     long long ret=0,now=0,c,d;
 54     while((d=Spfa())!=INF){
 55         c=Aug();
 56         if(c*d+now<0)
 57             return ret-now/d;
 58         else{ret+=c;now+=c*d;}
 59     }
 60     return ret;    
 61 }
 62 
 63 
 64 bool Get_ID(int x){
 65     bool ret=true;
 66     for(int i=2,m=(int)sqrt(x);i<=m;i++)
 67         if(x%i==0){while(x%i==0)x/=i,ret=!ret;}
 68     if(x!=1)ret=!ret;
 69     return ret;    
 70 }
 71 
 72 bool IS_Prime(int x){
 73     for(int i=2,m=(int)sqrt(x);i<=m;i++)
 74         if(x%i==0)return false;
 75     return true;    
 76 }
 77 
 78 int main(){
 79     scanf("%d",&n);S=0;T=n+1;
 80     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
 81     for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
 82     for(int i=1;i<=n;i++)scanf("%lld",&c[i]);
 83     for(int i=1;i<=n;i++)ID[i]=Get_ID(a[i]);
 84     for(int i=1;i<=n;i++){
 85         if(!ID[i]){
 86             addedge(S,i,b[i],0);addedge(i,S,0,0);
 87             for(int j=1;j<=n;j++)
 88                 if(ID[j]){
 89                     long long x=a[i],y=a[j];if(x<y)swap(x,y);
 90                     if(x%y==0&&IS_Prime(x/y)){
 91                         addedge(i,j,INF,c[i]*c[j]);
 92                         addedge(j,i,0,-c[i]*c[j]);
 93                     }
 94                 }
 95         }
 96         else{addedge(i,T,b[i],0);addedge(T,i,0,0);}
 97     }
 98     printf("%lld\n",MCMF());
 99     return 0;
100 }

 

posted @ 2016-06-11 19:10  TenderRun  阅读(231)  评论(0编辑  收藏  举报