博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SDOI2016]数字配对
阅读量:5159 次
发布时间:2019-06-13

本文共 3528 字,大约阅读时间需要 11 分钟。

1464677-20190301214802504-777852267.png

题解

一道有意思的网络流

首先一眼匹配类问题数据范围不大就想到网络流
但是发现了一个问题
一个数字只能参与一次匹配
所以继续从原题中发现条件
如果\(ai/aj\)是质数才会连边
那么我们就可以考虑对每个数质因数分解
\(t[i]\)表示\(i\)的每个质因子的幂的和
那么可以发现能连边的点\((i,j)\)一定满足\(|t[i]-t[j]|=1且a[i]|a[j]或a[j]|a[i]\)
那么这么一来就可以看出来是二分图了
\(S->t[i]%2=1 \\t[i]%2=0->T\)
然后再把可以配对的点连上
直接最大费用最大流跑就行了
然后题目还有一个限制条件:要满足价值不小于0
所以我们就在每次找到一条增广路的时候看流完这条增广路会不会使价值小于0
如果小于0则找一个使价值不小于0的流量流完这条增广路然后退出

代码

#include
#include
#include
#include
#include
# define LL long longconst int M = 255 ;const int N = 100005 ;const int INF = 1e8 ;using namespace std ;inline int read() { char c = getchar() ; int x = 0 , w = 1 ; while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; } while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; } return x*w ;}queue < int > q ;bool vis[M] , notp[N] ;int pnum , pri[N] ;int n , a[M] , b[M] , c[M] , t[M] ;int S , T , num = 1 , hea[M] , cnt , pre[M] ;LL dis[M] , mc , mf , ans ;struct E { int nxt , to ; LL dis , cst ; } edge[N] ;inline void add_edge(int from , int to , LL dis , LL cst) { edge[++num].nxt = hea[from] ; edge[num].to = to ; edge[num].dis = dis ; edge[num].cst = cst ; hea[from] = num ;}inline void Insert(int u , int v , LL w , LL c) { add_edge(u , v , w , -c) ; add_edge(v , u , 0 , c) ;}inline int Calc(int n) { int ret = 0 ; for(int i = 1 ; n > 1 && 1LL * pri[i] * pri[i] <= n ; i ++) while(n % pri[i] == 0) n /= pri[i] , ++ ret ; if(n > 1) ++ ret ; return ret ;}inline void presolve(int n) { for(int i = 2 ; i <= n ; i ++) { if(!notp[i]) pri[++pnum] = i ; for(int j = 1 ; j <= pnum && 1LL * i * pri[j] <= n ; j ++) { notp[i * pri[j]] = true ; if(i % pri[j] == 0) break ; } }}inline bool spfa() { queue < int > q ; q.push(S) ; pre[T] = -1 ; memset(dis , 63 , sizeof(dis)) ; dis[S] = 0 ; while(!q.empty()) { int u = q.front() ; q.pop() ; vis[u] = false ; for(int i = hea[u] ; i ; i = edge[i].nxt) { int v = edge[i].to ; if(dis[v] > dis[u] + edge[i].cst && edge[i].dis > 0) { dis[v] = dis[u] + edge[i].cst ; pre[v] = i ; if(vis[v]) continue ; vis[v] = true ; q.push(v) ; } } } return (pre[T] > 0) ;}inline void Solve() { LL diss ; while(spfa()) { diss = INF ; for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) diss = min(diss , edge[pre[i]].dis) ; for(int i = T ; i != S ; i = edge[pre[i] ^ 1].to) edge[pre[i]].dis -= diss , edge[pre[i] ^ 1].dis += diss ; if(mc - dis[T] * diss < 0) { ans += min(diss , mc / dis[T]) ; break ; } mf += diss ; mc -= dis[T] * diss ; } ans += mf ;}int main() { presolve(100000) ; n = read() ; S = 0 , T = n + 1 ; for(int i = 1 ; i <= n ; i ++) a[i] = read() ; for(int i = 1 ; i <= n ; i ++) t[i] = Calc(a[i]) ; for(int i = 1 ; i <= n ; i ++) { b[i] = read() ; if(t[i] % 2) Insert(S , i , b[i] , 0) ; else Insert(i , T , b[i] , 0) ; } for(int i = 1 ; i <= n ; i ++) c[i] = read() ; for(int i = 1 ; i <= n ; i ++) { if(t[i] % 2 == 0) continue ; for(int j = 1 ; j <= n ; j ++) { if(t[j] % 2 == 0 && abs(t[j] - t[i]) == 1 && (a[i] % a[j] == 0 || a[j] % a[i] == 0)) Insert(i , j , INF , 1LL * c[i] * c[j]) ; } } Solve() ; printf("%lld\n",ans) ; return 0 ;}

转载于:https://www.cnblogs.com/beretty/p/10459011.html

你可能感兴趣的文章
5G边缘网络虚拟化的利器:vCPE和SD-WAN
查看>>
MATLAB基础入门笔记
查看>>
【UVA】434-Matty&#39;s Blocks
查看>>
Android开发技术周报 Issue#80
查看>>
hadoop2.2.0+hive-0.10.0完全分布式安装方法
查看>>
django知识点总结
查看>>
C++ STL stack、queue和vector的使用
查看>>
使用Reporting Services时遇到的小问题
查看>>
约瑟夫问题
查看>>
Arduino 报错总结
查看>>
树莓派Android Things物联网开发:树莓派GPIO引脚图
查看>>
矩阵快速幂---BestCoder Round#8 1002
查看>>
如何将应用完美迁移至Android P版本
查看>>
【转】清空mysql一个库中的所有表的数据
查看>>
基于wxPython的python代码统计工具
查看>>
淘宝JAVA中间件Diamond详解(一)---简介&快速使用
查看>>
Hadoop HBase概念学习系列之HBase里的宽表设计概念(表设计)(二十七)
查看>>
Kettle学习系列之Kettle能做什么?(三)
查看>>
Day03:Selenium,BeautifulSoup4
查看>>
awk变量
查看>>