[Bzoj4514][Sdoi2016]数字配对(费用流)
Posted lzdhydzzh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Bzoj4514][Sdoi2016]数字配对(费用流)相关的知识,希望对你有一定的参考价值。
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
把奇数个质因子 偶数个质因子的放两边,然后匹配。
一直跑费用流跑到变负就好。或者边权取反,跑到变正就好。
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]数字配对(费用流)的主要内容,如果未能解决你的问题,请参考以下文章
图论(费用流):BZOJ 4514 [Sdoi2016]数字配对