[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;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983678.html

浙公网安备 33010602011771号