BZOJ 4514: [Sdoi2016]数字配对
4514: [Sdoi2016]数字配对
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1606 Solved: 608
[Submit][Status][Discuss]
Description
Input
Output
一行一个数,最多进行多少次配对
Sample Input
2 4 8
2 200 7
-1 -2 1
Sample Output
HINT
n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5
Source
分析:
其实不难发现这是一个网络流的题目...
然后考虑如何建图...
我们发现题目中有用的信息大概就只有一句话了:
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
于是,我们考虑如何利用这句话...如果我们把$a_x$分解质因数,那么如果存在$\frac{a_i}{a_j}=p$,那么就代表$a_i$的$x$个质因子里面有$x-1$和$a_j$的指数相同,并且剩下的那个质因子的指数比$a_j$多$1$,于是,我们考虑记$f[i]$代表$a_i$的质因子指数之和,那么一定是$f[i]$为奇数的点和$f[i]$为偶数的点之间右边相连,这就告诉我们这是一张二分图...
于是我们从$S$向所有的$f[i]$为奇数的点连$<S,i,b[i],0>$的边,从$f[i]$为偶数的点向$T$连$<i,T,b[i],0>$的边,然后对于所有合法的点对之间从奇数$f[i]$向偶数$f[i]$连$<x,y,inf,c[x]*x[y]>的边,然后如果要满足费用不小于$0$,那么我们跑最大费用最大流,如果当前增广的流更新答案之后答案不合法就直接停止增广输出答案...
一定要抓住题目中给出的信息进行转化,多去考虑和算法有关的性质...
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
//by NeighThorn
#define inf 0x3f3f3f3f3f3f3f
using namespace std; const int maxn=200+5,maxm=32000+5,maxe=100000+5; int n,a[maxn],b[maxn],c[maxn];
int cnt,no[maxn],vis[maxm],pri[maxm];
int S,T,hd[maxn],fl[maxe],to[maxe],nxt[maxe],Min[maxn],from[maxn];
long long w[maxe],dis[maxn]; map<int,int> mp; inline void prework(void){
for(int i=2;i<=32000;i++){
if(!vis[i])
vis[i]=1,pri[++cnt]=i,mp[i]=1;
for(int j=1;j<=cnt&&pri[j]*i<=32000;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
} inline void add(int x,int y,int s,long long l){
w[cnt]= l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
} inline bool spfa(void){
for(int i=S;i<=T;i++) dis[i]=-inf,Min[i]=0x3f3f3f3f;
queue<int> q;q.push(S),dis[S]=0;vis[S]=1;
while(!q.empty()){
int top=q.front();q.pop();vis[top]=0;
for(int i=hd[top];i!=-1;i=nxt[i])
if(fl[i]&&dis[to[i]]<dis[top]+w[i]){
from[to[i]]=i;
dis[to[i]]=dis[top]+w[i];
Min[to[i]]=min(Min[top],fl[i]);
if(!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
return dis[T]!=-inf;
} inline long long find(void){
for(int i=T;i!=S;i=to[from[i]^1])
fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
return dis[T]*Min[T];
} inline int mcmf(void){
long long t,mincost=0,maxflow=0;
while(spfa()){
t=find();
if(mincost+t>=0) mincost+=t,maxflow+=Min[T];
else{
maxflow+=mincost/abs(dis[T]);
return maxflow;
}
}
return maxflow;
} signed main(void){
scanf("%d",&n);prework();S=0;
memset(hd,-1,sizeof(hd));T=n+1;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1,tmp;i<=n;i++){
tmp=a[i];
for(int j=1;j<=cnt;j++)
while(tmp%pri[j]==0)
no[i]++,tmp/=pri[j];
if(tmp>1) no[i]++,mp[tmp]=1;
}
for(int i=1;i<=n;i++)
if(no[i]&1)
add(S,i,b[i],0);
else
add(i,T,b[i],0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i]%a[j]==0&&mp.find(a[i]/a[j])!=mp.end()){
if(no[i]&1) add(i,j,0x3f3f3f3f,1LL*c[i]*c[j]);
else add(j,i,0x3f3f3f3f,1LL*c[i]*c[j]);
}
printf("%d\n",mcmf());
return 0;
}
By NeighThorn
BZOJ 4514: [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 是一个质数 ...
- BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)
BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...
- 4514: [Sdoi2016]数字配对
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
- 4514: [Sdoi2016]数字配对 费用流
链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4514 思路 EK直接贪心做 <0的时候加上剩余返回 二分图a->b的时候 把b- ...
- 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流
[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...
- 【BZOJ4514】[Sdoi2016]数字配对 费用流
[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ...
- AC日记——[Sdoi2016]数字配对 bzoj 4514
4514 思路: 很受伤现在,,测了那么多次不过的原因就是因为INF不够大: 解法有两种: 解法1: 把n个点按照质因数个数为奇或偶分为两个点集(很容易就可以想到): 然后,按照题目连边跑最大费用流: ...
- 【BZOJ 4514】[Sdoi2016]数字配对 费用流
利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?) #include <cstdio> #inc ...
随机推荐
- stm8编程tips(stvd)
编译完成时显示程序占用的flash和ram大小 将附件压缩包中的mapinfo.exe解压到stvd的安装路径\stvd中 在工程上点右键选settings 右侧的选项卡选择Linker,将categ ...
- 现代web开发需要学习的15大技术
现代Web开发需要学习的15大技术 2016-06-08 13:08 快进到现在,我发现现代web开发再一次将发生压倒性的改变.信息资讯的铺天盖地令人迷惑,尤其对于初学者而言.首要原因是新的框架,例如 ...
- android service笔记
1.service 默认在主线程运行,所以不能在service中直接做访问网络,操作文件等耗时操作,要另外开启线程 2.通过startservice开启的服务,一旦服务开启,这个服务和开启他的调用者之 ...
- 『Python Kivy』官方乒乓球游戏示例解析
本篇文章用于对Kivy框架官方所给出的一个「乒乓球」小游戏的源码进行简单地解析.我会尽可能的将方方面面的内容都说清楚.在文章的最下方为官方所给出的这个小游戏的教程以及游戏源码. 由于篇幅所限,本文只简 ...
- 【性能调优】一次关于慢查询及FGC频繁的调优经历
以下来分享一个关于MySQL数据库慢查询和FGC频繁的性能案例. 一.系统架构 一个简单的dubbo服务,服务提供者提供接口,并且提供接口的实现,提供方注册服务到Zookeeper注册中心,然后消费者 ...
- Ubuntu18.04 + CUDA9.0 + cuDNN7.3 + Tensorflow-gpu-1.12 + Jupyter Notebook深度学习环境配置
目录 一.Ubuntu18.04 LTS系统的安装 1. 安装文件下载 2. 制作U盘安装镜像文件 3. 开始安装 二.设置软件源的国内镜像 1. 设置方法 2.关于ubuntu镜像的小知识 三.Nv ...
- const 常量与 define常量的区别
c++中的常量可以使用const定义,也可以使用#define宏定义的方式:二者区别如下: - **区别** 1. const定义的常量有自己的数据类型,编译器可以对其进行严格的类型检查:但是defi ...
- python之*args和**kwargs参数,以及迭代器
*args让函数可以接受不限制多个位置参数,**kwargs让函数可以接受不限制多个关键字参数,用法如图 2.迭代器总结
- BZOJ 4592 SHOI2015 脑洞治疗仪 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4592 题意概述:需要维护一个01序列A,一开始A全部都是1.支持如下操作: 1.将区间[l ...
- POJ 2166 Heapsort(递推)
Description A well known algorithm called heapsort is a deterministic sorting algorithm taking O(n l ...