[SDOI2016]数字配对
发现要求配对的条件是这样
\]
我们考虑一下再来一个\(a_k\),满足
\]
显然\(a_i=a_jp_1,a_j=a_kp_2\),于是\(a_i=p_1p_2\times a_k\)
显然\(p_1p_2\)不会是一个质数,于是我们大胆得出一个结论,如果\(a_i\)能和\(a_j\)配对,那么\(a_i\)就不能和其他能和\(a_j\)配对的数配对
于是经过这样一番简单分析,发现这是一二分图
那么做法就很显然了,我们将这张图来一个黑白染色,之后按照题目要求连边就好了
至于这道题要求在费用为正的情况下流量最大,最大费用最大流只能保证最大流的时候费用最大,不能保证费用为正
但是我们知道\(spfa\)去增广出的最长路肯定越来越小,于是我们一旦发现当前费用乘上流量小于\(0\)了,以后就不可能再使得费用为正了,于是在这个之后判断一下剩余流量退出就好了
当然,由于只会写板子,还是边权取反的最小费用最大流好写
代码
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define int long long
const int maxn=205;
const int inf=99999999999;
inline int read() {
char c=getchar();int r=1,x=0;
while(c<'0'||c>'9') {if(c=='-') r=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return r*x;
}
std::vector<int> v[maxn];
std::queue<int> q;
struct E{int v,nxt,f;LL w;}e[205*205*10];
int head[maxn],d[maxn],vis[maxn];
int a[maxn],b[maxn],c[maxn],col[maxn];
int S,T,n,num=1;
inline void C(int x,int y,LL w,int f) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;
e[num].f=f,e[num].w=w;
}
inline void add(int x,int y,LL w,int f) {C(x,y,-1*w,f),C(y,x,w,0);}
inline int SPFA() {
for(re int i=S;i<=T;i++) vis[i]=0,d[i]=inf;
q.push(T),d[T]=0;
while(!q.empty()) {
int k=q.front();q.pop();vis[k]=0;
for(re int i=head[k];i;i=e[i].nxt)
if(e[i^1].f&&d[e[i].v]>d[k]+e[i^1].w) {
d[e[i].v]=d[k]+e[i^1].w;
if(!vis[e[i].v]) q.push(e[i].v),vis[e[i].v]=1;
}
}
return d[S]<inf;
}
int dfs(int x,int now) {
if(x==T||!now) return now;
int flow=0,ff;vis[x]=1;
for(re int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].v]&&e[i].f&&d[e[i].v]==d[x]+e[i^1].w) {
ff=dfs(e[i].v,min(now,e[i].f));
if(ff<=0) continue;
now-=ff,flow+=ff;e[i].f-=ff,e[i^1].f+=ff;
if(!now) break;
}
return flow;
}
inline int check(int x) {
if(x==1) return 0;
for(re int i=2;i*i<=x;i++)
if(x%i==0) return 0;
return 1;
}
void paint(int x,int now) {
col[x]=now;
for(re int i=0;i<v[x].size();i++)
if(col[v[x][i]]==2) paint(v[x][i],now^1);
}
signed main() {
n=read();T=n+1;
for(re int i=1;i<=n;i++) a[i]=read();
for(re int i=1;i<=n;i++) b[i]=read();
for(re int i=1;i<=n;i++) c[i]=read();
for(re int i=1;i<=n;i++)
for(re int j=1;j<=n;j++)
if(a[i]%a[j]==0&&check(a[i]/a[j]))
v[i].push_back(j),v[j].push_back(i);
for(re int i=1;i<=n;i++) col[i]=2;
for(re int i=1;i<=n;i++)
if(col[i]==2) paint(i,1);
for(re int i=1;i<=n;i++)
if(col[i]) add(S,i,0,b[i]);
else add(i,T,0,b[i]);
for(re int i=1;i<=n;i++) {
if(!col[i]) continue;
for(re int j=0;j<v[i].size();j++)
add(i,v[i][j],(LL)c[i]*(LL)c[v[i][j]],inf);
}
int t=0,ans=0,flag=1,F=0;
while(SPFA()) {
vis[T]=1;
while(vis[T]) {
for(re int i=S;i<=T;i++) vis[i]=0;
t=dfs(S,inf);
if(ans+t*d[S]>0) {
F+=(0-ans)/d[S];
flag=0;break;
}
ans+=t*d[S],F+=t;
}
if(!flag) break;
}
printf("%lld\n",F);
return 0;
}
[SDOI2016]数字配对的更多相关文章
- 图论(费用流):BZOJ 4514 [Sdoi2016]数字配对
4514: [Sdoi2016]数字配对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 820 Solved: 345[Submit][Status ...
- BZOJ 4514: [Sdoi2016]数字配对 [费用流 数论]
4514: [Sdoi2016]数字配对 题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数 ...
- 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流
[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...
- BZOJ 4514: [Sdoi2016]数字配对
4514: [Sdoi2016]数字配对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1606 Solved: 608[Submit][Statu ...
- 【BZOJ4514】[Sdoi2016]数字配对 费用流
[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ...
- BZOJ4514——[Sdoi2016]数字配对
有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的 ...
- bzoj4514 [Sdoi2016]数字配对
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
- BZOJ4514[Sdoi2016]数字配对——最大费用最大流
题目描述 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci ...
- bzoj4514 [Sdoi2016]数字配对(网络流)
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
- 4514: [Sdoi2016]数字配对
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
随机推荐
- 如鹏网学习笔记(十三)EasyUI
一.EasyUI简介 是一组基于JQuery的UI插件集合 主要作用:为JQuery对象提供新的方法,实现新的功能 可以快速创建出简洁.友好.美观的页面,非常适合做网站后台管理页面(不够漂亮,不适合做 ...
- WAMP配置httpd.conf允许外部访问
在电脑上开启Apache服务后,如何让外部网络访问呢? 在网上查找答案和问过一些小伙伴后,得到以以下方案.大致是在httpd.conf中加入一些语句以及利用自己的WiFi建立热点,让需要访问的设备连接 ...
- Java学习--Java 中的包装类
Java 中的包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的,比如基本类型不能调用方法.功能简 ...
- C++ 语法积累20161015
1.break 作用:用于终止当前循环(跳出循环体). 遇到最多的应该是在双层循环体中的使用: (1)在内循环体中,遇到break,则直接跳出内循环体,再次执行外循环体. (2) 在外循环体中,bre ...
- windows emacs 中拷贝文件
cp d:/workspace/LoginWeb/target/LoginWeb.war D:/Program\ Files/apache-tomcat-7.0.78/webapps/LoginWeb ...
- RN canvas画布大小之谜
一.需求 在一个高640.宽360的canvas内画一些坐标点. 二.问题 坐标点只显示了一部分,剩下的点没显示(其坐标属于(640,360)区域). 三.原因 canvas默认的画布大小是高150, ...
- js-js的运算
** js里面不区分整数和小数 var j = 123; alert(j/1000*1000); //在Java里面结果是0 //在js里面不区分整数和小数 123/1000 = 0.123 *100 ...
- Dinic算法----最大流常用算法之一
——没有什么是一个BFS或一个DFS解决不了的:如果有,那就两个一起. 最大流的$EK$算法虽然简单,但时间复杂度是$O(nm^2)$,在竞赛中不太常用. 竞赛中常用的$Dinic$算法和$SAP$, ...
- 30个优秀的chrome网页设计开发插件
BuiltWith Resolution Test colorPicker Palette for Chrome Chrome Sniffer JS Library Detector Google F ...
- drupal7 获取当前使用的主题的名称
直接引用全局变量就行: 参考: 代码测试: global $theme, $theme_key; echo $theme; echo '<br>'; echo $theme_key; 结果 ...