4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1606  Solved: 608
[Submit][Status][Discuss]

Description

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

Input

第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。 

Output

一行一个数,最多进行多少次配对

Sample Input

3
2 4 8
2 200 7
-1 -2 1

Sample Output

4

HINT

n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

Source

鸣谢Menci上传

分析:

其实不难发现这是一个网络流的题目...

然后考虑如何建图...

我们发现题目中有用的信息大概就只有一句话了:

若两个数字 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]数字配对的更多相关文章

  1. 图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

    4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status ...

  2. BZOJ 4514: [Sdoi2016]数字配对 [费用流 数论]

    4514: [Sdoi2016]数字配对 题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数 ...

  3. BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)

    BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...

  4. 4514: [Sdoi2016]数字配对

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

  5. 4514: [Sdoi2016]数字配对 费用流

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4514 思路 EK直接贪心做 <0的时候加上剩余返回 二分图a->b的时候 把b- ...

  6. 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

    [bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...

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

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

  8. AC日记——[Sdoi2016]数字配对 bzoj 4514

    4514 思路: 很受伤现在,,测了那么多次不过的原因就是因为INF不够大: 解法有两种: 解法1: 把n个点按照质因数个数为奇或偶分为两个点集(很容易就可以想到): 然后,按照题目连边跑最大费用流: ...

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

    利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?) #include <cstdio> #inc ...

随机推荐

  1. Java的框架是什么意思

    框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现. JAVA框架可以分为三层:表示层,业务层和物理层.框架又叫做开发中的半成品,它不能提供整个WEB应用程序的所有东西,但是有了框 ...

  2. LaTeX工具——mathpix安利

    官网: https://mathpix.com/ 效果看下图: 图片打不开点这里 识别效果还行,感觉很适合jbc/zcy这种不喜欢打LaTex公式的神仙.

  3. Qt Creater 制作汽车仪表盘

    最近项目用到了模拟仪表,网上下载大神编写的按个仪表Meter没有成功 转战 QWt 编译后,在creater中仍然无法使用,只可以在代码中使用 百度说是我编译的版本不对 扔到 开始做自己的 这个用到了 ...

  4. C变量之间的转换

    int main(){ //定义了三个变量分别是abc ab的值分别是5跟8 c没有赋值  把b的值给c 把a的值给b 把c的值给a 形成了一个ab值得转换: int a=5; int b=8; in ...

  5. LeetCode 206——反转链表

    对单链表进行反转有迭代法和递归法两种. 1. 迭代法 迭代法从前往后遍历链表,定义三个指针分别指向相邻的三个结点,反转前两个结点,即让第二个结点指向第一个结点.然后依次往后移动指针,直到第二个结点为空 ...

  6. python之time和os模块

    1.time.time()获得的是一个时间戳,距离1970年以来多少秒 2.time.strftime(),按固定格式设置时间 import time print(time.localtime())# ...

  7. SQL SERVER 查询语句学习:CHARINDEX

    场景介绍 项目A需要一个批量删除的功能,之前我一直用SqlTransaction去处理,今天同事告诉我可以用CHARINDEX函数去解决问题,因此我今天就研究了一下. SQL语句 ---定义要删除的数 ...

  8. 手动修改PHP页面返回状态码

    <?php //比如当前页面要返回404状态码 header("HTTP/1.1 404 Not Found"); header("Status: 404 Not ...

  9. vuex中获取的数据使用v-model绑定出问题

    get selectedProp() { return this.$store.state.selectedProp; } 获取的数据selectedProp直接绑定在表单元素上会有错,因为不能直接对 ...

  10. 【bzoj4750】密码安全 单调栈

    题目描述 模10^9+61 输入 第一行包含一个正整数 T ,表示有 T 组测试数据. 接下来依次给出每组测试数据.对于每组测试数据: 第一行包含一个正整数 n . 第二行包含 n 个非负整数,表示 ...