版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oidoidoid/article/details/83153244
是一个二分图匹配
而我和舟神bbbbbbbbbbbbbbbbb了大概一个小时,不想写二分图,甚至想建网络流模型
我也是服了,可能这就是不会算时间复杂度的菜鸡吧
题目思路:
1.打素数表
2.将奇数和偶数分开到两边,因为只有奇数加偶数才可以是素数。
3.1特殊处理,如果有两个1,1之间也可以匹配,但优先考虑1和偶数的匹配,此处要注意细节,我用了两个set来减少讨论
#include<iostream>
#include<set>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#define N 3005
#define MAXN 2000005
using namespace std;
int eve[N],odd[N];
bool isprime[MAXN];
int prime[150005],tot=0;
void init(){
memset(isprime,true,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=MAXN-1;i++){
if(isprime[i]){
prime[++tot]=i;
}
for(int j=1;j<=tot;j++){
if(i*prime[j]>MAXN-1) break;
isprime[i*prime[j]]=0;
if(i%prime[j]==0) break;
}
}
//for (int i=1;i<=20;i++) cout<<i<<" "<<isprime[i]<<endl;
}
int head[N];
struct edge{
int v,next;
}e[N*N];
void add(int u, int v){
e[++tot]=(edge){v,head[u]};
head[u]=tot;
}
bool vis[N];
int link[N];
int dfs(int s){
//vis[s]=1; ?????
for(int i=head[s];i!=-1;i=e[i].next){
int t=e[i].v;
if(!vis[t]){
vis[t]=1;
if(link[t]==-1||dfs(link[t])){
link[t]=s;
link[s]=t;
return 1;
}
}
}
return 0;
}
int max_matching(int n)
{
int ans=0;
for(int i=1;i<=n;i++){
if (link[i]==-1){
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
}
return ans;
}
set<int>sodd,seven;
int main(){
init();
int T;
scanf("%d",&T);
while (T--){
int n,k,tot1=0,tot2=0,x;
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x%2) odd[++tot1]=x;
else eve[++tot2]=x;
}
tot=0;
memset(head,-1,sizeof(head));
sodd.clear();
seven.clear();
int last1=-1,sum1=0;
for (int i=1;i<=tot1;i++){
if (odd[i]==1){
if (!sum1) last1=i,sum1++;
else{
if (sum1==1) sodd.insert(last1);
sodd.insert(i);
sum1++;
}
}
for (int j=1;j<=tot2;j++){
if (isprime[odd[i]+eve[j]]){
add(i,tot1+j);
add(tot1+j,i);
sodd.insert(i);
seven.insert(j);
}
}
}
memset(link,-1,sizeof(link));
int mat=max_matching(tot1);
//cout<<mat<<endl;
//for (int i=1;i<=tot1+tot2;i++) printf("link%d\n",link[i]);
if (mat>=k) printf("%d\n",k*2);
else{
int tmp=0;
for (int i=1;i<=tot1;i++){
if (odd[i]==1&&link[i]==-1) tmp++;
}
int ans=mat*2+tmp/2*2;
if (ans>=2*k) printf("%d\n",k*2);
else {
ans=min(k*2,min(ans+k-mat-tmp/2,(int)sodd.size()+(int)seven.size()));
printf("%d\n",ans);
}
}
}
return 0;
}
/*
10
5 5
1 1 1 1 1
6 5
1 1 1 1 2 2
6 3
1 1 1 1 1 3
6
5 5
1 1 1 1 1
*/