Loading

[JSOI2016]反质数序列

链接:https://www.luogu.com.cn/problem/P5771

题目描述:在一个序列中求一个子序列\(x\)使得对于任意数对\((i,j)\)都有\(x_{i}+x_{j}\)不为质数。

题解:话说这题则么这么卡常,我到现在都还是\(80\)分。

读完题我们发现,假如对\((i,j)\)连一条\(x_{i}+x_{j}\)是否为质数的边的话,原问题就转化为了最大独立集。

最大独立集?\(NPC\)?边权一定有某些性质。

我们知道如果一个数是质数,那么这个数不是奇数就是\(2\)

先考虑全为奇数的情况:

\(a+b\)是奇数,\(b+c\)是奇数,那么\(a+c\)就一定是偶数,所以原图不存在三元环,同理可以推出五元环,七元环等的情况。按照这样的方法推,我们可以得到原图没有奇环。

再考虑边权为\(2\)的边:

\(x_{i}+x_{j}=2\),则有\(x_{i}=x_{j}=1\),那么所有的\(1\)都会连一条边,其实它就是一个团,那么我们可以把它缩成一个点。

然后这个图就变为了二分图,因为二分图最大独立集\(=\)n-\(二分图最大匹配\),所以可以按\(x_{i}\)的奇偶性分为两部分,跑网络流就可以求出最大匹配了。

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct node
{
	int v,data,nxt;
};
node edge[20000001];
int a[3001],len,head[3002],depth[3002],color[3002],n,N,s,t;
bool prime[200001],used[3002];
inline bool cmp(register int a,register int b)
{
	return a>b;
}
inline void add(register int x,register int y,register int z)
{
	edge[++len].v=y;
	edge[len].data=z;
	edge[len].nxt=head[x];
	head[x]=len;
	return;
}
inline bool bfs()
{
	register int top;
	queue<int>q;
	for (register int i=s;i<=t;++i)
		depth[i]=0;
	q.push(s);
	depth[s]=1;
	while (!q.empty())
	{
		top=q.front();
		q.pop();
		for (register int i=head[top];i>0;i=edge[i].nxt)
			if (edge[i].data&&!depth[edge[i].v])
			{
				depth[edge[i].v]=depth[top]+1;
				if (edge[i].v==t)
					return 1;
				q.push(edge[i].v);
			}
	}
	return 0;
}
inline int dinic(register int x,register int flow)
{
	if (x==t)
		return flow;
	register int res=flow,k;
	for (register int i=head[x];i>0;i=edge[i].nxt)
		if (edge[i].data&&depth[edge[i].v]==depth[x]+1)
		{
			k=dinic(edge[i].v,min(res,edge[i].data));
			if (k==0)
				depth[edge[i].v]=0;
			res-=k;
			edge[i].data-=k;
			edge[i^1].data+=k;
		}
	return flow-res;
}
inline int read()
{
	register int sum=0;
	register char c=0;
	while (c<'0'||c>'9')
		c=getchar();
	while ('0'<=c&&c<='9')
	{
		sum=sum*10+c-'0';
		c=getchar();
	}
	return sum;
}
int main()
{ 
	len=1;
	for (register int i=2;i<=2e5;++i)
		if (!prime[i])
		{
			for (int j=i*2;j<=2e5;j+=i)
				prime[j]=1;
		}
	n=read();
	N=n;
	for (register int i=1;i<=n;++i)
		a[i]=read();
	sort(a+1,a+n+1,cmp);
	for (register int i=n;i>=1;--i)
		if (a[i-1]==1)
			N--;
	s=0;
	t=N+1; 
	for (register int i=1;i<=N;++i)
		for (register int j=1;j<=N;++j)
			if (!prime[a[i]+a[j]]&&a[i]%2==0&&a[j]%2==1)
			{
				add(i,j,1);
				add(j,i,0);
			}
	for (register int i=1;i<=N;++i)
	{
		if (a[i]%2==0)
		{
			add(s,i,1);
			add(i,s,0);
		}
		else
		{
			add(i,t,1);
			add(t,i,0);
		}
	}
	register int flow,maxflow=0;
	while (bfs())
		while (flow=dinic(s,1e9))
			maxflow+=flow;
	printf("%d\n",N-maxflow);
	return 0;
}
posted @ 2022-12-14 21:40  zhouhuanyi  阅读(36)  评论(0)    收藏  举报