[ABC263G] Erasing Prime Pairs

Problem Statement

There are integers with $N$ different values written on a blackboard. The $i$-th value is $A_i$ and is written $B_i$ times.

You may repeat the following operation as many times as possible:

  • Choose two integers $x$ and $y$ written on the blackboard such that $x+y$ is prime. Erase these two integers.

Find the maximum number of times the operation can be performed.

Constraints

  • $1 \leq N \leq 100$
  • $1 \leq A_i \leq 10^7$
  • $1 \leq B_i \leq 10^9$
  • All $A_i$ are distinct.
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

$N$ 
$A_1$ $B_1$
$A_2$ $B_2$
$\vdots$
$A_N$ $B_N$

Output

Print the answer.


Sample Input 1

3
3 3
2 4
6 2

Sample Output 1

3

We have $2 + 3 = 5$, and $5$ is prime, so you can choose $2$ and $3$ to erase them, but nothing else. Since there are four $2$s and three $3$s, you can do the operation three times.


Sample Input 2

1
1 4

Sample Output 2

2

We have $1 + 1 = 2$, and $2$ is prime, so you can choose $1$ and $1$ to erase them. Since there are four $1$s, you can do the operation twice.

既然要判断质数,一个肯定要做的操作就是把 \(2\times10^7\) 之内的质数筛出来。不妨把和为质数的两个点连条边。边相连的两个点的点权可以同时减去一个数,要保证点权为正数,问最多操作次数。

手动模拟一下,有网络流的感觉。于是考虑最大流解决。把第 \(i\) 种数拆成两个点,第一个点编号为 \(i\),第二个点编号为 \(n+i\)。对于第 \(i\) 个数,从源点 \(s\) 连一条流量为 \(b_i\) 的边,从 \(i+n\) 连一条流量为 \(b_i\) 的边至汇点 \(t\)。如果 \(a_i+a_j\) 为质数,从 \(i\) 连一条流量为 \(+\infty\) 的边至 \(j+n\)。然后跑一次最大流,得出答案后除以 \(2\) 就是答案。

为什么要除以 \(2\)?由于我们计算最大流时,\(a_i+a_j\) 若为质数,那么 \(i\)\(j+n\) 的边中算了一次,\(j+n\)\(i\) 的边中算了一次。所以算了两次。

但是我们没考虑 \(1+1=2\)?其实计算最大流时已经计算。须要两个 \(1\) 才能有一次删除机会,而我们最后也除以了 \(2\)。所以不需要特殊判断。

#include<bits/stdc++.h>
using namespace std;
const int N=205,M=40005,P=2e7+5;
int n,m,s,t,k,g,hd[N],l,r,v[N],q[N],vhd[N],uu,vv,ww,e_num=1,p[P],p_num,pri[P],a[N],b[N],ee;
struct edge{
	int v,nxt,w;
}e[M<<1];
void add_edge(int u,int v,int w)
{
	e[++e_num]=(edge){v,hd[u],w};
	hd[u]=e_num;
}
long long ans;
int bfs()
{
	memset(v,0,sizeof(v));
	memcpy(hd,vhd,sizeof(hd));
	q[l=r=1]=s,v[s]=1;
	while(l<=r)
	{
		if(q[l]==t)
			break;
		for(int i=hd[q[l]];i;i=e[i].nxt)
			if(e[i].w>0&&!v[e[i].v])
				q[++r]=e[i].v,v[e[i].v]=v[q[l]]+1;
		++l;
	}
	return v[t];
}
int dfs(int x,int s)
{
//	printf("%d %d\n",x,s);
	if(x==t)
		return s;
	int b,c;
	for(int&i=hd[x];i;i=e[i].nxt)
	{
		b=e[i].v,c=min(s,e[i].w);
		if(v[b]==v[x]+1&&c>0)
		{
			g=dfs(b,c);
			if(g)
			{
				e[i].w-=g;
				e[i^1].w+=g;
				return g;
			}
			else
				v[b]=0;
		}
	}
	return 0;
}
signed main()
{
	scanf("%d",&n);
	s=0,t=2*n+1;
	for(int i=2;i<P;i++)
	{
		if(!pri[i])
			p[++p_num]=i;
		for(int j=1;j<=p_num&&1LL*p[j]*i<P;j++)
		{
			pri[p[j]*i]=1;
			if(i%p[j]==0)
				break;
		}
	}
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",a+i,b+i);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(!pri[a[i]+a[j]])
			{
				add_edge(i,n+j,2e9);
				add_edge(j+n,i,0);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		add_edge(s,i,b[i]);
		add_edge(i,s,0);
	}
	for(int i=1;i<=n;i++)
	{
		add_edge(i+n,t,b[i]);
		add_edge(t,i+n,0);
	}
	memcpy(vhd,hd,sizeof(hd));
	while(bfs())
	{
		while(k=dfs(s,2e9))
			ans+=k;
	}
	printf("%lld",ans/2);
	return 0;
}
posted @ 2022-09-12 22:02  灰鲭鲨  阅读(46)  评论(0编辑  收藏  举报