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. IIS 应用程序池.NET40 重新注册

    32位的Windows:---------------------------------------------------------------------------1. 运行->cmd ...

  2. ISAPI_Rewrite中文手册

    参考:http://blog.csdn.net/fanxiaojie119/article/details/5353186 第一章:软件介绍ISAPI_Rewrite 是一款适用于IIS的功能强大的基 ...

  3. 10 个迅速提升你 Git 水平的提示

    1. Git自动补全 假使你使用命令行工具运行Git命令,那么每次手动输入各种命令是一件很令人厌烦的事情.为了解决这个问题,你可以启用Git的自动补全功能,完成这项工作仅需要几分钟. 为了得到这个脚本 ...

  4. java的守护线程与非守护线程

    最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) ,(PS:以 ...

  5. vtk renderer / rendering 绘制

    1.在绘制窗口中绘制出物体(静态的)vtkRenderWindow * w=vtkRenderWindow::New();  w->AddRenderer(r);        for(int ...

  6. Theano2.1.5-基础知识之打印出theano的图

    来自:http://deeplearning.net/software/theano/tutorial/printing_drawing.html Printing/Drawing Theano gr ...

  7. c#邮件发送的实现

    第一步 :引用命名空间 using System.Net; using System.Net.Mail; 第二步:具体代码 //创建邮箱信息 MailMessage myMail = new Mail ...

  8. 眼保Guide

    1.睡前不要玩手机,特别是关灯玩手机!否则第二天早上你就会感到眼睛模糊了.长久下去就会形成近视或者近视加深. 2.早上起床半小时内不要戴眼镜,不要看手机.电脑等一切电子屏幕,甚至不要看书.这段时间是眼 ...

  9. WampServer下如何实现多域名配置(虚拟域名配置)

    之前在学习跨域的时候,我写过一篇叫做WampServer下使用多端口访问的文章,默认的 localhost 采用的是 80 端口,能使用多端口访问的核心是得新建一个端口,也就是新建一个 http 服务 ...

  10. C#微信开发小白成长教程一(公众平台的工作原理与调试环境部署,附视频)

    黑夜给了我黑色的眼睛,我决定录视频到天明.半年前的现在,我还在苦逼着加着班,半年后的今天我依旧苦逼着加着班.不过现在的是为自己加班,作为一个资深程序小白,一个月前我光荣的成了一个不称职的资本家,不称职 ...