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. TraceHelper

    public class TraceHelper { private static TraceHelper _traceHelper; private TraceHelper() { } public ...

  2. Selenium 入门到精通系列:五

    Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...

  3. Django学习总结- ③

    对象属性与继承关系: 对象属性 1. 显示属性 - 开发者手动定义的,直接看的到的 2. 隐式属性 - 系统根据需求,自动创建的对象 - objects 它是model.Manager对象 - 当我们 ...

  4. servlet和Jsp的复习整理

    servlet 1.生命周期 a.构造方法.生成一个servlet b.init()方法.当开启服务器时,servlet第一次被装载,servlet引擎调用这个servlet的init()的方法,只调 ...

  5. 【转】巫师3:狂猎(The Witcher 3: Wild Hunt )的游戏事件工作流

    转自腾讯游戏开发者平台(GAD) CDPROJEKT RED的主程序.Piotr Tomsinski 在GDC2016的最后一天18号,CDPROJEKT RED的主程Piotr Tomsinski, ...

  6. python程序设计——文件操作

    分类 1.文本文件 存储常规字符串,由若干文本行组成,每行以换行符'\n'结尾 2.二进制文件 把对象以字节串存储,常见的图形图像.可执行文件.数据库文件office文档等 #创建文件 >> ...

  7. CSP201703-1:分蛋糕

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  8. 校招小白机考入坑之从键盘输入java的各种数据类型

    //1.从键盘输入一个整型(其他基本类型类似) Scanner sc =new Scanner(System.in); sc.hasNextInt(); int str1 = sc.nextInt() ...

  9. Python+Flask+Gunicorn 项目实战(一) 从零开始,写一个Markdown解析器 —— 初体验

    (一)前言 在开始学习之前,你需要确保你对Python, JavaScript, HTML, Markdown语法有非常基础的了解.项目的源码你可以在 https://github.com/zhu-y ...

  10. opencv-学习笔记(3)

    opencv-学习笔记(3) 这章讲了 图像加法 opencv测试效率 IPYTHON测试效率 图像加法 cv2.add() 要求,两图片必须大小类型相同 然后是图像混合cv2.addWeighted ...