AT2689 Prime Flip

时间:2021-06-05 15:25:54

传送门

这个题是真的巧妙

首先一个很巧妙的思路,差分

考虑假如\(a_i!=a_{i-1}\),则\(b_i=1\),否则\(b_i=0\)

这样一来,一个区间的翻转就变成了对于两个数的取反了

然后我们来考虑一下取反的代价(没错这个题我就只想到了这个)

1、假如距离是奇质数,只要1步,显然

2、假如距离是偶数,引用一下哥德巴赫猜想,2步即可

3、假如距离是奇合数,就是3步(奇质数+偶数)

显然我们可以把这些\(b_i=1\)的按照奇偶性分为2组

组内距离一定是奇数,组与组之间可能是奇质数也可能是奇合数

但是我们显然需要距离为奇质数最多,所以考虑将两组间距离为奇质数的连边,跑二分图最大匹配

然后假设最大匹配是\(k\),两组的size分别是\(size1,size2\)

那么答案显然是\(ans=k+\lfloor\frac{size1-k}{2}\rfloor*2+\lfloor\frac{size2-k}{2}\rfloor*2+(size1-k)\%2*3\)

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
void read(int &x){
char ch;bool ok;
for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
}
#define rg register
const int maxn=210;bool vis[maxn];
int f[maxn],n,ans,a[maxn],mp[maxn][maxn],b[maxn],tot1,tot2,x[maxn];
bool check(int x){
if((!(x&1))||x==1)return 0;
int n=sqrt(x);
for(rg int i=2;i<=n;i++)
if(!(x%i))return 0;
return 1;
}
bool dfs(int x){
for(rg int i=1;i<=tot2;i++)
if(!vis[i]&&mp[x][i]){
vis[i]=1;
if(!f[i]||dfs(f[i]))return f[i]=x,1;
}
return 0;
}
int main(){
read(n);
for(rg int i=1;i<=n;i++)read(x[i]);
if(n==1){printf("3\n");return 0;}
for(rg int i=1;i<=n;i++){
if(x[i+1]-x[i]!=1||i==n){
if((x[i]+1)%2==0)a[++tot1]=x[i]+1;
else b[++tot2]=x[i]+1;
}
if(x[i]-x[i-1]!=1||i==1){
if(x[i]&1)b[++tot2]=x[i];
else a[++tot1]=x[i];
}
}
for(rg int i=1;i<=tot1;i++)
for(rg int j=1;j<=tot2;j++)
if(check(abs(a[i]-b[j])))mp[i][j]=1;
for(rg int i=1;i<=tot1;i++){
memset(vis,0,sizeof vis);
if(dfs(i))ans++;
}
printf("%d\n",ans+(tot1-ans)/2*2+(tot2-ans)/2*2+(tot1-ans)%2*3);
}