To_Heart—题解——JSOI2016 反质数序列

题目

题目链接

题解

因为同奇偶的数相加一定是偶数,所以一定是合数,(1+1特判)

我们可以把序列中的分为奇数和偶数两部,并可以确定每个部之间肯定不可以都选,所以我们就把它转换成了一个二分图的问题。

我们再将两个数相加可能为合数的情况建边,再求一个最大独立子集就可以了。

#include<bits/stdc++.h>
using namespace std;

int a[3005];
int b[3005];
int t[3005];
int n=0,m=0;
int len;
bool p[1000005]={
    
    };

void Prime(){
    
    
	for(int i=2;i<=200000;i++){
    
    
		if(p[i])
			continue;
		for(int j=i*2;j<=200000;j+=i)
			p[j]=1;
	}
}

int vis[3005][3005]={
    
    };
vector<int> v[3005]; 
int flag[3005]={
    
    };
int f[3005]={
    
    };	
int ans=0;

bool DFS(int x){
    
    
	for(int i=0;i<v[x].size();i++){
    
    
		int y=v[x][i];
		if(f[y])
			continue;
		f[y]=1; 
		if(!flag[y]||DFS(flag[y])){
    
    
			flag[y]=x;
			return 1;
		}
	}
	return 0;
}

void Work(){
    
    
	bool f=1;
	for(int i=1;i<=len;i++){
    
    
		if(t[i]==1){
    
    
			if(f)
				a[++n]=t[i];
			f=0;
			continue;
		}
		if(t[i]%2)
			a[++n]=t[i];
		else
			b[++m]=t[i];
	}
}

int main(){
    
    
	Prime();
	cin>>len;
	for(int i=1;i<=len;i++){
    
    
		scanf("%d",&t[i]);
	}
	Work();
	for(int i=1;i<=n;i++){
    
    
		for(int j=1;j<=m;j++){
    
    
			if(!p[a[i]+b[j]]){
    
    
				v[i].push_back(j);
			}
		}
	}
	memset(flag,0,sizeof flag);
	for(int i=1;i<=n;i++){
    
    
		memset(f,0,sizeof f);
		if(DFS(i))
			ans++;
	}
	printf("%d\n",n+m-ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xf2056188203/article/details/115018142