1. 程式人生 > >[Bzoj4514][Sdoi2016]數字配對(費用流)

[Bzoj4514][Sdoi2016]數字配對(費用流)

-c true res turn code input mit sizeof ons

4514: [Sdoi2016]數字配對


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

Source


鳴謝Menci上傳

分析:


通過這道題我明白了這類題要去構造二分圖模型。。 把奇數個質因子 偶數個質因子的放兩邊,然後匹配。 一直跑費用流跑到變負就好。或者邊權取反,跑到變正就好。 wa在了把局部變量和整體變量定義一樣了,還得了70,下次註意點把。

AC代碼:


# include <iostream>
# include <cstdio>
# include <cmath>
# include <cstring>
using namespace
std; typedef long long LL; const int N = 212; const LL Inf = 1e18; int a[N],n,cnt,prime[32001],s,t,one[N],two[N],head[N],dt; bool vis[32001];LL c[N],b[N]; struct Edge{ int to,nex;LL res,cost; }edge[N * N * 4]; void AddEdge(int u,int v,LL w,LL c) { edge[dt] = (Edge){v,head[u],w,c}; head[u] = dt++; edge[dt] = (Edge){u,head[v],0,-c}; head[v] = dt++; } void shai() { for(int i = 2;i <= 32000;i++) { if(!vis[i])prime[++cnt] = i; for(int j = 1;j <= cnt;j++) { if(i * prime[j] > 32000)break; vis[i * prime[j]] = true; if(i % prime[j] == 0)break; } } } void init(){shai();memset(head,-1,sizeof head);} void divide() { for(int i = 1;i <= n;i++) { int sum = 0,x = a[i]; for(int j = 1;j <= cnt;j++) { if(prime[j] > x)break; while(x % prime[j] == 0)x /= prime[j],sum++; } if(sum & 1)one[++one[0]] = i,AddEdge(s,i,b[i],0); else two[++two[0]] = i,AddEdge(i,t,b[i],0); } } bool pd(int x,int y) { if(!x || !y || (x % y && y % x))return false; int k = max(x / y,y / x); if(k == 1)return false; for(int i = 1;i <= cnt;i++)if(prime[i] >= k)break; else if(k % prime[i] == 0)return false; return true; } int que[N * 10000],pre[N];LL dis[N]; bool spfa() { for(int i = s;i <= t;i++)vis[i] = 0,pre[i] = -1,dis[i] = Inf; int H = 0,T = 0,u;que[T++] = s;dis[s] = 0; while(H != T) { u = que[H++];vis[u] = false; for(int i = head[u];~i;i = edge[i].nex)if(edge[i].res && dis[edge[i].to] > dis[u] + edge[i].cost) { dis[edge[i].to] = dis[u] + edge[i].cost; pre[edge[i].to] = i; if(!vis[edge[i].to])vis[edge[i].to] = true,que[T++] = edge[i].to; } } return pre[t] != -1; } void Mcmf(LL &ans,LL &cost) { ans = cost = 0; while(spfa()) { LL tmp = Inf; for(int i = pre[t];~i;i = pre[edge[i ^ 1].to]) tmp = min(tmp,edge[i].res); if(cost + dis[t] * tmp <= 0) { for(int i = pre[t];~i;i = pre[edge[i ^ 1].to]) edge[i].res -= tmp,edge[i ^ 1].res += tmp; ans += tmp; cost += dis[t] * tmp; } else {ans -= (cost / dis[t]);return;} } } int main() { scanf("%d",&n);init();s = 0;t = n + 1; for(int i = 1;i <= n;i++)scanf("%d",&a[i]); for(int i = 1;i <= n;i++)scanf("%lld",&b[i]); for(int i = 1;i <= n;i++)scanf("%lld",&c[i]); divide(); for(int i = 1;i <= one[0];i++) { for(int j = 1;j <= two[0];j++) if(pd(a[one[i]],a[two[j]])) AddEdge(one[i],two[j],Inf,-c[one[i]] * c[two[j]]); } LL ans,cost; Mcmf(ans,cost); printf("%lld\n",ans); }

[Bzoj4514][Sdoi2016]數字配對(費用流)