【bzoj4514】[Sdoi2016]数字配对 费用流
来源:互联网 发布:网络用语mmp是什么意思 编辑:程序博客网 时间:2024/06/05 09:35
题意
给n个数,他们互不相同,第i个数是a[i],有b[i]个,权值为c[i]。两个数可以配对当且仅当a[i]是a[j]的倍数且a[i]/a[j]是素数,它们配对所产生的权值是c[i]*c[j]。每次配对消耗一个数。求权值不小于0的情况下最大配对数量。
样例输入
32 4 82 200 7-1 -2 1
样例输出
4
数据范围
30%:暴力,b[i]=1
60%:c[i]=0
100%:n<=200,a[i]<=10^9,b[i]<=10^5,c[i]<=10^5
我竟然没看出来是二分图……
唯一分解后的指数之和的奇偶性可以自然而然的二分图染色,想到这点就很容易做了……
然后可配对点之间连边,流量INF。源点向指数之和是奇数的点连容量是b[i]的边,偶数的点向汇点连是b[i]的边,然后跑最大流就50分了。
顺着这个思路就很好想……既然要有权值,肯定在INF边上加上c[i]*c[j]的权值。因为跑最大费用流的时候是从费用最大的路径先增广,所以费用是单调不升的,所以在费用大于0且最小的时候的流量就是答案。
longlong坑爹。
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#include<cmath>using namespace std;typedef long long LL;const int SZ = 1000010;const LL INF = 100000000000000010;int n;int head[SZ],nxt[SZ];struct edge{ int f,t; LL d,c;}l[SZ];void build(int f,int t,LL d,LL c){ static int tot = 1; l[++ tot].f = f; l[tot].t = t; l[tot].d = d; l[tot].c = c; nxt[tot] = head[f]; head[f] = tot;}void insert(int f,int t,LL d,LL c){ build(f,t,d,c); build(t,f,0,-c);}bool use[SZ];LL dist[SZ];int pre[SZ];queue<int> q;bool spfa(int s,int e){ memset(dist,-128,sizeof(dist)); dist[s] = 0; use[s] = 1; q.push(s); while(q.size()) { int u = q.front(); q.pop(); use[u] = 0; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(l[i].d && dist[v] < dist[u] + l[i].c) { dist[v] = dist[u] + l[i].c; pre[v] = i; if(!use[v]) { use[v] = 1; q.push(v); } } } } return dist[e] < -INF ? false : true;}LL cost = 0;LL dfs(int s,int e){ LL flow = INF; for(int i = pre[e];i;i = pre[l[i].f]) flow = min(flow,l[i].d); if(cost + flow * dist[e] < 0) flow = -cost / dist[e]; cost += flow * dist[e]; for(int i = pre[e];i;i = pre[l[i].f]) l[i].d -= flow,l[i ^ 1].d += flow; return flow;}LL EK(int s,int e){ LL ans = 0; while(spfa(s,e)) { LL tmp = dfs(s,e); if(tmp == 0) break; ans += tmp; } return ans;}int a[SZ];LL c[SZ],b[SZ];bool jojo[SZ];int zys(int n){ int x = n; int ans = 0; for(int i = 2;i <= sqrt(x);i ++) { while(n % i == 0) { n /= i; ans ++; } } if(n != 1) ans ++; return ans;}bool ispri(int x){ for(int i = 2;i <= sqrt(x);i ++) if(x % i == 0) return false; return true;}int main(){ scanf("%d",&n); 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]); for(int i = 1;i <= n;i ++) jojo[i] = zys(a[i]) % 2; int s = n + 1,e = n + 2; for(int i = 1;i <= n;i ++) { if(jojo[i] == 1) insert(s,i,b[i],0); else insert(i,e,b[i],0); } for(int i = 1;i <= n;i ++) { for(int j = i + 1;j <= n;j ++) { if(jojo[i] ^ jojo[j]) { if(a[i] % a[j] == 0 && ispri(a[i] / a[j])) { if(jojo[i]) insert(i,j,INF,c[i] * c[j]); else insert(j,i,INF,c[i] * c[j]); } if(a[j] % a[i] == 0 && ispri(a[j] / a[i])) { if(jojo[i]) insert(i,j,INF,c[i] * c[j]); else insert(j,i,INF,c[i] * c[j]); } } } } printf("%lld\n",EK(s,e)); return 0;}/*32 4 82 200 7-1 -2 1*/
0 0
- 【bzoj4514】[Sdoi2016]数字配对 费用流
- [BZOJ4514] [SDOI2016] 数字配对 - 费用流
- 费用流 【SDOI2016】 bzoj4514 数字配对
- Bzoj4514:[Sdoi2016]数字配对:网络流,费用流
- [bzoj4514][SDOI2016]数字配对
- BZOJ4514 [Sdoi2016]数字配对
- bzoj4514【SDOI2016】数字配对
- BZOJ4514: [Sdoi2016]数字配对
- BZOJ4514 [Sdoi2016]数字配对
- bzoj4514: [Sdoi2016]数字配对
- BZOJ4514: [Sdoi2016]数字配对
- 【BZOJ4514】数字配对,费用流
- bzoj4514 数字配对 费用流
- BZOJ4514:数字配对(费用流+数学)
- BZOJ4514——[Sdoi2016]数字配对
- 4514: [Sdoi2016]数字配对|费用流
- bzoj 4514: [Sdoi2016]数字配对 费用流
- [二分图 费用流] BZOJ 4514 [Sdoi2016]数字配对
- 项目22--友元类
- java数据结构和算法目录(持续更新中)
- easyUI框架下实现日期按年,年月,年月日方式显示
- 第七周项目2友元类
- 搜狐 扎金花
- 【bzoj4514】[Sdoi2016]数字配对 费用流
- DOM启蒙——第三章
- kafka-manager免构建包
- 静态数据成员的应用
- Swift接口和扩展
- Django ModelAdmin 中设置字段的默认值
- 剑指offer系列之35:两个链表的第一个公共节点
- 初学者理解throw和throws
- linux 5种查找命令