4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 726  Solved: 309
[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上传

Solution

二分图建图方式,分析一下

如果$a[i]$和$a[j]$互质,不妨把它们分解质因子,互质即质因子约去后的质因子互质,或者只剩一个质因子

所以考虑先预处理 线性筛质数,再质因数分解,含有奇数个质因子的与含有偶数个质因子的分列两排

如果满足$a[i]$和$a[j]$可连($a[i]$为质因数为奇的$a[j]$为质因数为偶的),则由$i--->j$连容量$inf$,费用$c[i]*c[j]$

由$S--->odd[i]$连容量$b[odd[i]]$,费用为$0$;同理$even[i]--->T$连容量$b[even[i]]$费用$0$

然后跑最大费用最大流,因为最大费用最大流每次增广的路径费用严格不下降,所以,贪心的一直跑到总费用$<=0$的时候,单独判断一下即可

容易出问题的细节:

1.注意开longlong...

2.Inf的范围要注意(习惯性的开0x7fffffff导致WA5组...)

3.不能暴力筛和暴力分解,时间复杂度不科学

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 1010
#define maxm 100010
int n,a[maxn],b[maxn];long long c[maxn]; bool f=;
struct EdgeNode{int next,cap,to,from;long long cost;}edge[maxm];
int head[maxn],cnt=;
void add(int u,int v,int w,long long c)
{
cnt++;
edge[cnt].to=v;edge[cnt].from=u;edge[cnt].cap=w;edge[cnt].cost=c;edge[cnt].next=head[u];head[u]=cnt;
}
void insert(int u,int v,int w,long long c) {add(u,v,w,c); add(v,u,,-c);}
int from[maxn],S,T; long long dis[maxn]; bool mark[maxn];
#define inf 10000000000000LL
bool spfa()
{
queue<int>q;
for (int i=S; i<=T; i++) dis[i]=-inf; memset(from,,sizeof(from));
q.push(S); mark[S]=; dis[S]=;
while (!q.empty())
{
int now=q.front(); q.pop(); mark[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]<dis[now]+edge[i].cost)
{
dis[edge[i].to]=dis[now]+edge[i].cost; from[edge[i].to]=i;
if (!mark[edge[i].to])
q.push(edge[i].to),mark[edge[i].to]=;
}
}
return dis[T]!=-inf;
}
long long Cost; int Flow;
void MaxCostFlow()
{
int flow=inf;
for (int i=from[T]; i; i=from[edge[i].from])
flow=min(flow,edge[i].cap); if ((long long)Cost+flow*dis[T]>=0LL)
{
for (int i=from[T]; i; i=from[edge[i].from])
edge[i].cap-=flow,edge[i^].cap+=flow;
Flow+=flow; Cost+=dis[T]*flow; }
else
Flow+=abs(Cost/dis[T]),Cost-=(Cost/dis[T])*dis[T],f=;
// Flow+=flow;
//printf("%d %I64d %I64d\n",Flow,Cost,dis[T]);
}
int prime[],tot; bool flag[];
void Prework()
{
flag[]=;
for (int i=; i<=; i++)
{
if (!flag[i]) prime[++tot]=i;
for (int j=; j<=tot&&i*prime[j]<=; j++)
flag[i*prime[j]]=;
}
}
int odd[maxn],even[maxn],ot,et;
bool check(int x,int y)
{
if (x%y && y%x || !x || !y) return ;
int tmp=max(x/y,y/x);
for (int i=; i<=tot&&prime[i]<tmp; i++)
if (tmp%prime[i]==) return ;
return ;
}
void Build()
{
Prework();
S=,T=n+;
for (int i=,ct=; i<=n; i++,ct=)
{
for (int j=,tmp=a[i]; j<=tot; j++,tmp=a[i])
while (tmp%prime[j]==) tmp/=prime[j],ct++;
//else if (prime[j]>tmp) break;
if (ct&) odd[++ot]=i; else even[++et]=i;
}
for (int i=; i<=ot; i++)
for (int j=; j<=et; j++)
if (check(a[odd[i]],a[even[j]]))
insert(odd[i],even[j],inf,c[odd[i]]*c[even[j]])/*,printf("%d-->%d:%d/%I64d\n",odd[i],even[j],inf,c[odd[i]]*c[even[j]])*/;
for (int i=; i<=ot; i++) insert(S,odd[i],b[odd[i]],0LL)/*,printf("%d-->%d:%d/%I64d\n",S,odd[i],b[odd[i]],0LL)*/;
for (int i=; i<=et; i++) insert(even[i],T,b[even[i]],0LL)/*,printf("%d-->%d:%d/%I64d\n",even[i],T,b[even[i]],0LL)*/;
//printf("%d %d %d\n",ot,et,cnt);
}
int main()
{
// freopen("menci_pair.in","r",stdin);
// freopen("menci_pair.out","w",stdout);
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]=(long long)read();
Build();
while (spfa() && !f) MaxCostFlow();
printf("%d\n",Flow);
return ;
}

当时唯一想出和出题人一模一样的解法的题,但是最后不知道莫名其妙的写错了什么地方,结果连暴力分都不到....(回来之后这么久才想起来重写一遍..)

【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛的更多相关文章

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

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

  2. bzoj 4514: 数字配对

    题目大意 自己看 题解 我们打表观察规律发现一定能构成一张二分图 也就是不存在奇环 所以我们一般保证费用非负的最大流即可. #include <cstdio> #include <c ...

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

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

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

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

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

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

  6. BZOJ 1927 星际竞速(最小费用最大流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1927 题意:一个图,n个点.对于给出的每条边 u,v,w,表示u和v中编号小的那个到编号 ...

  7. BZOJ 2424: [HAOI2010]订货(最小费用最大流)

    最小费用最大流..乱搞即可 ------------------------------------------------------------------------------ #includ ...

  8. 【BZOJ4514】数字配对(费用流)

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

  9. [SDOI2016]数字配对(费用流+贪心+trick)

    重点是如何找到可以配对的\(a[i]\)和\(a[j]\). 把\(a[i]\)分解质因数.设\(a[i]\)分解出的质因数的数量为\(cnt[i]\). 设\(a[i]\geq a[j]\) 那么\ ...

随机推荐

  1. CentOS下OpenVPN客户端配置

    CentOS下OpenVPN客户端配置 http://liumissyou.blog.51cto.com/4828343/1762683 1,安装 yum install openvpn -y mkd ...

  2. scala 学习笔记(05) OOP(中)灵活的trait

    trait -- 不仅仅只是接口! 接上回继续,scala是一个非常有想法的语言,从接口的设计上就可以发现它的与众不同.scala中与java的接口最接近的概念是trait,见下面的代码: packa ...

  3. async 更优雅异步体验

    上一篇<让 Generator 自启动>介绍了通过起动器让 Generator 跑起来,而本篇采用 async 实现更优雅的异步编程. 从例子开始 借用上一篇例子中的例子说起. funct ...

  4. 最小/大费用最大流模板(codevs1914)

    void addedge(int fr,int to,int cap,int cos){ sid[cnt].fr=fr;sid[cnt].des=to;sid[cnt].cap=cap;sid[cnt ...

  5. centos 服务器内存管理

    du su /目录/ 查看改目录大小 ls -lht /  查看文件详情,显示文件大小(直观) df -h 查看系统内存占用情况

  6. Linux终端更改提示符

    打开~/.bashrc可以看到命令提示的内容为:\u@\h\w\$ \u表示用户名,\h表示主机名,\w表示当前目录,\$表示命令提示符(普通用户$,超级用户#) 这个命令提示符有点长,很碍事,\u@ ...

  7. 曾经post为何只能通过form来提交

    当我们web程序的前台,需要有数据向后台发送时候,我们第一时间想到的就是,给我们所需要提交的用户名,密码之类的数据封装到一个<form>表单里面去,而封装完毕之后,我们需要给form的提交 ...

  8. chgrp 简明笔记

    改变与文件相关联的组 chgrp [options] group file-list 参数 group 为新组的名称或者数值ID,file-list 为要改变其相关联组的文件路径名列表 选项 -c   ...

  9. directly receive json data from javascript in mvc

    if you send json data to mvc,how can you receive them and parse them more simply? you can do it like ...

  10. 0924Linux常用命令

    写的不错 转载了,有需要的同学们,可以多多学习,适合小白哦 http://blog.csdn.net/xiaoguaihai/article/details/8705992/ 关于最后增加一点 tar ...