Prime Flip
题解
挺简单的
很容易发现,如果要将一个点
i
i
i翻转的话,需要进行
[
1
,
i
]
[1,i]
[1,i],
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]个区间翻转。
我们可以先将所有的翻转给列出来,消去相同的翻转,很明显剩下的翻转数一定是偶数。
我们可以将翻转两两匹配,将翻转
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]与
[
1
,
r
]
[1,r]
[1,r]匹配在一起,变成对区间
[
l
,
r
]
[l,r]
[l,r]的翻转。
对于翻转一个区间 [ l , r ] [l,r] [l,r],我们需要分三种情况讨论:
1.若 r − l + 1 r-l+1 r−l+1为奇质数,一步即可。
2.若 r − l + 1 r-l+1 r−l+1为偶数,根据哥德巴赫猜想,两步即可(额外考虑 2 = 5 − 3 , 4 = 7 − 3 2=5-3,4=7-3 2=5−3,4=7−3)。
3.若 r − l + 1 r-l+1 r−l+1为奇非质数,减去一个奇质数,变成偶数的情况,3步即可(额外考虑 1 = 7 − 3 − 3 1=7-3-3 1=7−3−3)。
由于第1种情况的权值是最小的,我们想尽可能将翻转都匹配为第1种情况。
由于第一种情况同一区间的两个翻转奇偶性一定是不同的,我们可以根据翻转位置的奇偶建二分图,将相差为奇质数的翻转连边,最后再跑二分图最大匹配,看能匹配多少。
对于匹配到的两个翻转,作为第一种情况。匹配不了的再同奇偶之间匹配,作为第2种情况。
最后最多也只会让奇和偶之间各多出一个,作为第3种情况匹配。
由于总的翻转次数为偶数,所以一定可以全部匹配完。
时间复杂度 O ( n 3 ) O\left(n^3\right) O(n3)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 205
#define MAXM 10000005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,a[MAXN],b[MAXN],idx,c[MAXN],d[MAXN],cntc,cntd,ans,p[MAXN];
int prime[MAXM/10],cntp,head[MAXN],tot;bool oula[MAXM],vis[MAXN];
struct edge{int to,nxt;}e[MAXN*MAXN];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void init(){
oula[1]=1;
for(int i=2;i<=1e7;i++){
if(!oula[i])prime[++cntp]=i;
for(int j=1;j<=cntp&&prime[j]*i<=1e7;j++){
oula[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
bool misaka(int x){
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(p[e[i].to]==-1||(!vis[p[e[i].to]]&&misaka(p[e[i].to])))
return (p[e[i].to]=x,1);
return 0;
}
int sakura(){
int res=0;for(int i=1;i<=cntd;i++)p[i]=-1;
for(int i=1;i<=cntc;i++){
for(int j=1;j<=cntc;j++)vis[j]=0;
if(misaka(i))res++;
}
return res;
}
signed main(){
read(n);for(int i=1,x;i<=n;i++)read(x),a[i*2-1]=x-1,a[i*2]=x;
init();sort(a+1,a+2*n+1);
for(int i=1;i<=2*n;i++){if(a[i]==a[i+1]){i++;continue;}b[++idx]=a[i];}
for(int i=1;i<=idx;i++)((b[i]&1)?c[++cntc]:d[++cntd])=b[i];
for(int i=1;i<=cntc;i++)
for(int j=1;j<=cntd;j++)
if(!oula[Fabs(c[i]-d[j])])addEdge(i,j);
int tmp=sakura();ans+=tmp;cntc-=tmp;cntd-=tmp;
ans+=2*(cntc/2+cntd/2);cntc&=1;if(cntc)ans+=3;
printf("%d\n",ans);
return 0;
}