https://www.lydsy.com/JudgeOnline/problem.php?id=4514

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

参考洛谷题解。

这题很明显是要网络流的,且将关系图建出来之后很明显是二分图。

那么我们自然的将点归为两类,一类连S,一类连T,这样我们的边就有了方向性,然后就可以跑最大费用最大流了!

但是难受的是,我们跑的费用要求始终不低于0,这就很难办,我们简单的费用流无法胜任这个工作。

但是可以发现的是,我们spfa找可行流的时候,显然是先走大费用路径再走小费用路径,于是我们在spfa上直接跑网络流,一边更新dis,一边记录当前节点流入了多少,显然每次只能跑出来一条路径一个流因此会比原版费用流慢很多,复杂度O(玄学)反正能过。

以及我们当然不必要将二分图建出来dfs,我们记录tot[i]表示第i个数的质因子个数,则奇数为一堆偶数为一堆即可。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=1e9;
const ll LINF=1e18;
const int N=;
const int M=N*N*;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to,nxt,w;
ll b;
}e[M];
int n,head[N],cnt,a[N],b[N],c[N],tot[N],limit[N],pre[N];
ll dis[N];
bool vis[N];
inline void add(int u,int v,int w,ll b){
e[++cnt].to=v;e[cnt].w=w;e[cnt].b=b;e[cnt].nxt=head[u];head[u]=cnt;
e[++cnt].to=u;e[cnt].w=;e[cnt].b=-b;e[cnt].nxt=head[v];head[v]=cnt;
}
int suan(int k){
int ans=;
for(int i=;i*i<=k;i++){
while(k%i==){
ans++;k/=i;
}
}
if(k!=)ans++;
return ans;
}
inline bool spfa(int s,int t,int m){
queue<int>q;
memset(vis,,sizeof(vis));
memset(pre,-,sizeof(pre));
for(int i=;i<=m;i++)dis[i]=-LINF;
limit[s]=INF;dis[s]=;q.push(s);vis[s]=;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=;
for(int i=head[u];i!=-;i=e[i].nxt){
int v=e[i].to;ll b=e[i].b;
if(e[i].w&&dis[v]<dis[u]+b){
dis[v]=dis[u]+b;
limit[v]=min(limit[u],e[i].w);
pre[v]=i;
if(!vis[v])
vis[v]=,q.push(v);
}
}
}
return dis[t]>-LINF;
}
inline int costflow(int S,int T,int m){
int flow=,delta;ll ans=;
while(spfa(S,T,m)){
if(ans+dis[T]<)break;
if(dis[T]>=)delta=limit[T];
else delta=min((ll)limit[T],ans/(-dis[T]));
ans+=dis[T]*delta;flow+=delta;
for(int u=T;pre[u]!=-;u=e[pre[u]^].to){
e[pre[u]].w-=delta;e[pre[u]^].w+=delta;
}
}
return flow;
}
int main(){
memset(head,-,sizeof(head));cnt=-;
n=read();
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<=n;i++)b[i]=read();
for(int i=;i<=n;i++)c[i]=read();
for(int i=;i<=n;i++)tot[i]=suan(a[i]);
int S=n+,T=S+;
for(int i=;i<=n;i++){
if(tot[i]&)add(S,i,b[i],);
else add(i,T,b[i],);
if(tot[i]&){
for(int j=;j<=n;j++){
if((a[j]%a[i]==&&tot[i]+==tot[j])||
(a[i]%a[j]==&&tot[j]+==tot[i]))
add(i,j,INF,(ll)c[i]*c[j]);
}
}
}
printf("%d\n",costflow(S,T,T));
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4514:[SDOI2016]数字配对——题解的更多相关文章

  1. [bzoj4514][SDOI2016]数字配对——二分图

    题目描述 传送门 题解: 这个题真的是巨坑,经过了6个WA,2个TLE,1个RE后才终于搞出来,中间都有点放弃希望了... 主要是一定要注意longlong! 下面开始说明题解. 朴素的想法是: 如果 ...

  2. BZOJ4514 [Sdoi2016]数字配对 【费用流】

    题目 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×c ...

  3. BZOJ4514——[Sdoi2016]数字配对

    有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的 ...

  4. bzoj4514 [Sdoi2016]数字配对

    Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...

  5. BZOJ4514[Sdoi2016]数字配对——最大费用最大流

    题目描述 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci ...

  6. bzoj4514 [Sdoi2016]数字配对(网络流)

    Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...

  7. bzoj4514: [Sdoi2016]数字配对--费用流

    看了一眼题目&数据范围,觉得应该是带下界的费用流 原来想拆点变成二分图,能配对的连边,跑二分图,可行性未知 后来看到另外一种解法.. 符合匹配要求的数要满足:质因子的个数相差为1,且两者可整除 ...

  8. bzoj4514: [Sdoi2016]数字配对(费用流)

    传送门 ps:费用流增广的时候费用和流量打反了……调了一个多小时 每个数只能参与一次配对,那么这就是一个匹配嘛 我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数 ...

  9. 【BZOJ4514】[Sdoi2016]数字配对 费用流

    [BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ...

随机推荐

  1. Android 9 Pie震撼来袭 同步登陆WeTest

    WeTest 导读 2018年8月7日,Google对外发布最新 Android 9.0 正式版系统,并宣布系统版本Android P 被正式命名为代号“Pie”,最新系统已经正式推送包括谷歌Pixe ...

  2. 引领技术变革,腾讯云、腾讯WeTest和英特尔,合作布局云游戏

    WeTest 导读 ChinaJoy作为中国泛娱乐产业年度风向标,受到全球业界的高度关注.在本届ChinaJoy上,腾讯云.腾讯WeTest和英特尔,合作为游戏玩家.游戏开发者等业界人士联合展出了云游 ...

  3. 创建并运行第一个Django项目

    首先, 添加Django模块: 在CMD命令行输入 python -m django --version 查看Django版本: 创建第一个Django项目: 整个工程的目录结构: mysite目录是 ...

  4. requests,lxml爬启信宝

    首先, 添加requests模块: 然后, 添加lxml模块: 启信宝登录抓包: QiXinBao.py: import requestsfrom lxml import etree loginUrl ...

  5. Monkey用真机做测试的步骤

    1 必备条件 1) 手机需要先获取root权限: 2) 手机和电脑相连(电脑可以访问手机里面的文件) 2  操作步骤 1) 使用adb devices 命令查看电脑手机是否相连: 下图表示手机已连上电 ...

  6. Selenium 入门到精通系列:六

    Selenium 入门到精通系列 PS:Checkbox方法 例子 HTML: <html> <head> <title>测试页面</title> &l ...

  7. Linux命令应用大词典-第3章 文本编辑器

    3.1 vi:文本编辑器 3.2 nano:编辑器 3.3 view:文办编辑器 3.4 ex:文本编辑器 3.5 ed:文本编辑器 3.6 red:文本编辑器 3.1 vi:文本编辑器 1.对文本创 ...

  8. CodeForces - 913C(二进制)

    链接:CodeForces - 913C 题意:给出 n 瓶饮料的花费 C 数组,每瓶的体积是 2^(i-1) 升,求至少买 L 升的最少花费. 题解:二进制数的组合可以表示任何一个数.第 i 的饮料 ...

  9. 单词 (Play on Words UVA - 10129 )

    题目描述: 原题:https://vjudge.net/problem/UVA-10129 题目思路: 1.明显是判断欧拉路径 2.欧拉路径的两个条件 a.图连通 b.至多为两个奇点,且一个为起点一个 ...

  10. 【Linux 运维】 安装PHP工具Composer

    一.安装PHP 由于Composer是 PHP 用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的 ...