bzoj4514【SDOI2016】数字配对

4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB

Submit: 730  Solved: 311

[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上传

费用流的应用

对于所有数字,可以分为两类,分解质因数后指数和为奇数和偶数。配对关系也只能在两类之间,于是就构成一个二分图的模型。建图之后跑费用流就可以了。

这里还有一个限制,费用总和不小于0,也就是每一步要让费用尽可能大。所以我们将所有费用取反,然后每次SPFA后判断是否会使费用大于0,这样就可以保证了费用的限制。

注意程序第81行的ans-=(cost/dis[t])。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 210
#define maxm 30000
#define inf 1000000000000000000ll
using namespace std;
int n,s,t,cnt=1,tot,totx,toty,ans;
int a[maxn],b[maxn],head[maxn],p[maxn],pri[32005],fx[maxn],fy[maxn];
ll c[maxn],dis[maxn];
bool inq[maxn],vst[32005];
struct edge_type{int next,from,to,v;ll c;}e[maxm];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline bool judge(int x,int y)
{
	if (!x||!y) return false;
	if (x<y) swap(x,y);
	if (x%y!=0) return false;
	x/=y;
	F(i,1,tot)
	{
		if (pri[i]>=x) break;
		if (x%pri[i]==0) return false;
	}
	return true;
}
inline void add_edge(int x,int y,int v,ll c)
{
	e[++cnt]=(edge_type){head[x],x,y,v,-c};head[x]=cnt;
	e[++cnt]=(edge_type){head[y],y,x,0,c};head[y]=cnt;
}
inline bool spfa()
{
	queue<int> q;
	memset(inq,false,sizeof(inq));
	F(i,1,t) dis[i]=inf;
	dis[s]=0;inq[s]=true;q.push(s);
	while (!q.empty())
	{
		int x=q.front();q.pop();inq[x]=false;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (e[i].v&&dis[y]>dis[x]+e[i].c)
			{
				dis[y]=dis[x]+e[i].c;
				p[y]=i;
				if (!inq[y]) q.push(y),inq[y]=true;
			}
		}
	}
	return dis[t]!=inf;
}
inline void mcf()
{
	ll cost=0;
	while (spfa())
	{
		int tmp=1000000000;
		for(int i=p[t];i;i=p[e[i].from]) tmp=min(tmp,e[i].v);
		if (cost+dis[t]*tmp<=0)
		{
			cost+=dis[t]*tmp;ans+=tmp;
			for(int i=p[t];i;i=p[e[i].from]) e[i].v-=tmp,e[i^1].v+=tmp;
		}
		else
		{
			ans-=(cost/dis[t]);
			return;
		}
	}
}
int main()
{
	n=read();
	s=n+1;t=n+2;
	F(i,1,n) a[i]=read();
	F(i,1,n) b[i]=read();
	F(i,1,n) c[i]=read();
	F(i,2,32000)
	{
		if (!vst[i]) pri[++tot]=i;
		F(j,1,tot)
		{
			if (i*pri[j]>32000) break;
			vst[i*pri[j]]=true;
			if (i%pri[j]==0) break;
		}
	}
	F(i,1,n)
	{
		int tmp=a[i],num=0;
		F(j,1,tot)
		{
			while (tmp%pri[j]==0) tmp/=pri[j],num++;
			if (tmp==1) break;
		}
		if (num&1) fx[++totx]=i;
		else fy[++toty]=i;
	}
	F(i,1,totx) F(j,1,toty) if (judge(a[fx[i]],a[fy[j]])) add_edge(fx[i],fy[j],1000000000,c[fx[i]]*c[fy[j]]);
	F(i,1,totx) add_edge(s,fx[i],b[fx[i]],0);
	F(i,1,toty) add_edge(fy[i],t,b[fy[i]],0);
	mcf();
	printf("%d\n",ans);
}
时间: 2024-08-07 10:26:57

bzoj4514【SDOI2016】数字配对的相关文章

[Bzoj4514][Sdoi2016]数字配对(费用流)

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2204  Solved: 865[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

bzoj4514 [Sdoi2016]数字配对(网络流)

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.--

BZOJ4514: [Sdoi2016]数字配对(费用流)

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2197  Solved: 859[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最

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

题目 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进行多少次配对. 输入格式 第一行一个整数 n. 第二行 n 个整数 a1.a2.--.an. 第三行 n 个整数 b1.b2.--.bn. 第四行 n 个整数 c1.c2.--.cn. 输出格式

[bzoj4514] [Sdoi2016]数字配对

费用流.. 先把a数组里的数全部质因数分解,判断ai/aj是否为质数,就看质因数互相抵消后是不是只剩一个质因数. 满足条件的数就连边 接下来我想拆点建二分图..然而由题解可得,连边的两个数 的质因数个数 的奇偶性肯定不同.. 就相当于自带黑白染色...所以奇数个连汇,偶数个连源就行了= = 因为有价值总和不小于0的限制.所以找到一条价值为负的增广路后,不一定能流满. 但是因为求费用流的原始对偶算法自带限制流量的功能..所以其实改一个数就能照常多路增广了= = 1 #include<cstdio>

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

[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后能匹配的两点i,j 连 i->j' cap=inf cost=c[i]*c[j] 跑最大费用流,直到 cost<0 或 全部增广完 最后flow/2就是答案 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #i

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

[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进行多少次配对. Input 第一行一个整数 n. 第二行 n 个整数 a1.a2.…….an. 第三行 n 个整数 b1.b2.

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

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

4514: [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1305  Solved: 498[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 726  Solved: 309[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在