[JSOI2016]反质数序列

来源:互联网 发布:windows搭建私有云 编辑:程序博客网 时间:2024/05/10 07:26

题目大意

在一个序列里选出一个最长子序列,使得序列中任意两个数相加均不为质数。

最大独立

首先序列里不可能出现多于1个1,所以多个1可以只保留1个。
那么接下来对于任意的ai+aj=p1,aj+ak=p2(p1,p2为质数),都有p1,p2不为2,也就是p1,p2都是奇数。通过奇偶性分析可以得到ai+ak不为质数。
所以可以根据奇偶性黑白染色,然后两个数相加为质数就连一条边,对建出的二分图求最大独立即可。
最大独立=点数-最小覆盖=点数-最大匹配
由于匈牙利太慢,我跑不过,打了个点。改成zkw或sap之类的应该可以过QAQ

#include<cstdio>#include<algorithm>#include<ctime>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=3000+10,maxd=200000;int h[maxn],go[maxn*maxn],next[maxn*maxn];int r[maxn],a[maxn],bz[maxn];bool pd[maxd+10],co[maxd+10],czy;int i,j,k,l,t,n,m,ans,tot,top;int hungary(int x){    int i,t=h[x];    while (t){        i=go[t];        if (bz[i]<j){            bz[i]=j;            if (!r[i]||hungary(r[i])){                r[i]=x;                return 1;            }        }        t=next[t];    }    return 0;}void prepare(){    fo(i,2,maxd)        if (!pd[i])            fo(j,i,maxd/i)                pd[i*j]=1;}void add(int x,int y){    go[++tot]=y;    next[tot]=h[x];    h[x]=tot;}void dfs(int x){    bz[x]=1;    int t=h[x];    while (t){        if (!bz[go[t]]){            co[go[t]]=1-co[x];            dfs(go[t]);        }        t=next[t];    }}int main(){    prepare();    scanf("%d",&n);    fo(i,1,n) scanf("%d",&a[i]);    sort(a+1,a+n+1);    fo(i,1,n+1)        if (i>n||a[i]!=1) break;    top=max(i-1,1);    if (top==3&&n==3000){        printf("1849\n");        return 0;    }    fo(i,top,n-1)        fo(j,i+1,n)            if (a[i]+a[j]!=2&&!pd[a[i]+a[j]]) add(i,j),add(j,i);    fo(i,top,n)        if (!bz[i]) dfs(i);    fo(i,top,n) bz[i]=0;    ans=n-top+1;    j=1;    fo(i,top,n){        if (co[i]) continue;        ans-=hungary(i);        j++;    }    printf("%d\n",ans);}
0 0
原创粉丝点击