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. Richardson成熟度模型

    Richardson Maturity Model(RMM) 迈向REST的辉煌 一个模型(由Leonard Richardson开发)将REST方法的主要元素分解为三个步骤.这些引入资源,http动 ...

  2. .NET中发送邮件的实现

    .NET中发送邮件 注意: 1.引用下列命名空间: using System.Net; using System.Net.Mail; 2.确保你使用的发送邮件的邮箱开启了stamp服务等. /// & ...

  3. 教你一招,提升你Python代码的可读性,小技巧

    Python的初学者,开发者都应该知道的代码可读性提高技巧,本篇主要介绍了如下内容: PEP 8是什么以及它存在的原因 为什么你应该编写符合PEP 8标准的代码 如何编写符合PEP 8的代码 为什么我 ...

  4. python 终极篇 --- form组件 与 modelForm

                                                           form组件                                       ...

  5. Java学习 · 初识 IO流

    IO流   1. 原理与概念 a)     流 i.           流动,流向 ii.           从一端移动到另一端 源头到目的地 iii.           抽象.动态概念,是一连 ...

  6. 本地矩阵(Local Matrix)

    本地矩阵具有整型的行.列索引值和双精度浮点型的元素值,它存储在单机上.MLlib支持稠密矩阵DenseMatrix和稀疏矩阵Sparse Matrix两种本地矩阵,稠密矩阵将所有元素的值存储在一个列优 ...

  7. Android开发-API指南-<supports-screens>

    <supports-screens> 英文原文:http://developer.android.com/guide/topics/manifest/supports-screens-el ...

  8. beego 笔记

    1.开发文档 https://beego.me/docs/intro/ 2.bee run projectname demo controller package autoscaler import ...

  9. Ubuntu—终端命令调整窗口的大小

    1,查看窗口大小 current 1280x768 是我当前电脑的窗口大小,下面提供的是可以修改的窗口大小. $ xrandr 2.修改窗口大小 示例: $ xrandr -s 1024x768

  10. [递推+矩阵快速幂]Codeforces 1117D - Magic Gems

    传送门:Educational Codeforces Round 60 – D   题意: 给定N,M(n <1e18,m <= 100) 一个magic gem可以分裂成M个普通的gem ...