【BZOJ4514】【SDOI2016】数字配对 [费用流]

数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
[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

Solution

  显然是一个费用流,并且这可以是一个二分图,由于 ai/aj 要是质数,那显然可以根据质因子个数的奇偶分类。

  然后跑一跑最大费用最大流。判断一下值要>=0即可统计入答案。mmpBearChild查了一个下午错,发现是INF开小了qaq。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<map>
  9 using namespace std;
 10 typedef long long s64;
 11 #define next nxt
 12 const int N = 1005;
 13 const int M = 400005;
 14 const int INF = 2147483640;
 15 
 16 int n;
 17 int a[N], b[N], c[N];
 18 s64 dist[N];
 19 int vis[N], q[N], pre[N];
 20 int first[M], go[M], next[M], pas[M], from[M], tot;
 21 int pNum[M];
 22 int odd[M],Onum, eve[M],Enum;
 23 int S, T, Ans;
 24 int prime[M], isp[M], p;
 25 s64 Val, w[M];
 26 
 27 int get()
 28 {
 29     int res=1,Q=1;char c;
 30     while( (c=getchar())<48 || c>57 )
 31     if(c=='-')Q=-1;
 32     res=c-48;
 33     while( (c=getchar())>=48 && c<=57 )
 34     res=res*10+c-48;
 35     return res*Q;
 36 }
 37 
 38 void Getp(int MaxN)
 39 {
 40     for(int i=2; i <= MaxN; i++)
 41     {
 42         if(!isp[i]) prime[++p] = i;
 43         for(int j=1; j <= prime[p] && i*prime[j] <= MaxN; j++)
 44         {
 45             isp[i * prime[j]] = 1;
 46             if(i % prime[j] == 0) break;
 47         }
 48     }
 49 }
 50 
 51 int Factor(int x)
 52 {
 53     int res = 0;
 54     while(x != 1)
 55     {
 56         for(int i=1; i<=p; i++)
 57         if(x % prime[i] == 0)
 58         {
 59             x /= prime[i];
 60             res++;
 61             break;
 62         }
 63     }
 64     return res;
 65 }
 66 
 67 int PD(int x, int y)
 68 {
 69     if(x > y) swap(x, y);
 70     if(x==0 || y==0 || y%x!=0) return 0;
 71     x = y / x;
 72     for(int i=2; i<x; i++)
 73     if(x % i == 0) return 0;
 74     return 1;
 75 }
 76 
 77 void Add(int u, int v, int flow, s64 z)
 78 {
 79     next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  pas[tot]=flow;  w[tot]=z;   from[tot]=u;
 80     next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  pas[tot]=0;     w[tot]=-z;  from[tot]=v;
 81 }
 82 
 83 bool Bfs()
 84 {
 85     for(int i=S; i<=T; i++) dist[i] = -1e18;
 86     int tou = 0, wei = 1;
 87     q[1] = S;   vis[S] = 1; dist[S] = 0;
 88     while(tou < wei)
 89     {
 90         int u = q[++tou];
 91         for(int e=first[u]; e; e=next[e])
 92         {
 93             int v=go[e];
 94             if(dist[v] < dist[u] + w[e] && pas[e])
 95             {
 96                 dist[v] = dist[u] + w[e];
 97                 pre[v] = e;
 98                 if(!vis[v])
 99                 {
100                     q[++wei] = v;
101                     vis[v] = 1;
102                 }
103             }
104         }
105         vis[u] = 0;
106     }
107     return dist[T] != -1e18;
108 }
109 
110 void Deal()
111 {
112     int x = INF;
113     for(int e=pre[T]; e; e=pre[from[e]]) x = min(x, pas[e]);
114     if(Val + dist[T] * x >= 0)
115     {
116         for(int e=pre[T]; e; e=pre[from[e]])
117         {
118             pas[e] -= x;
119             pas[((e-1)^1)+1] += x;
120         }
121         Val += dist[T] * x;
122         Ans += x;
123         return;
124     }
125     printf("%lld", Ans - Val / dist[T]);
126     exit(0);
127 }
128 
129 int main()
130 {
131     Getp(M - 5);
132     n = get();
133     for(int i=1; i<=n; i++) a[i] = get(), pNum[i] = Factor(a[i]);
134     for(int i=1; i<=n; i++) b[i] = get();
135     for(int i=1; i<=n; i++) c[i] = get();
136 
137     S = 0; T = n+1;
138     for(int i=1; i<=n; i++)
139     {
140         if(pNum[i] & 1) Add(S,i, b[i],0), odd[++Onum] = i;
141         else Add(i,T, b[i],0), eve[++Enum] = i;
142     }
143 
144     for(int i=1; i<=Onum; i++)
145     for(int j=1; j<=Enum; j++)
146     {
147         int x = odd[i], y = eve[j];
148         if( PD(a[x], a[y]) )
149             Add(x,y, INF,(s64)c[x]*c[y]);
150     }
151 
152     while(Bfs()) Deal();
153     printf("%lld", Ans - Val / dist[T]);
154 }
View Code

 

  • 视图代码
posted @ 2017-06-04 17:18  BearChild  阅读(181)  评论(0编辑  收藏  举报