[ARC080D] Prime Flip
\(\text{Problem}:\)Prime Flip
\(\text{Solution}:\)
区间反转、取反等操作通常和差分有关。
记 \(b_{i}=(a_{i}\not = a_{i-1})(i\geq 1)\),特殊的,使得 \(b_{0}=0\),那么我们要使得 \(a\) 数组全部变为 \(0\) 等价于使得 \(b\) 数组全部变为 \(0\)。
现在的操作是对于 \(a\) 数组,可以反转一段区间 \([L,R]\),这等价于把 \(b_{L}\) 和 \(b_{R+1}\) 取反。那么题目转化为:现在 \(b\) 数组上有一些位置是 \(1\),你每次可以选择 \(b_{i},b_{j}\),满足 \(j-i\) 是奇质数,将\(b_{i},b_{j}\) 同时取反,求最少多少次能将 \(b\) 数组全部变为 \(0\)。
发现 \(b\) 数组上是 \(1\) 的位置一定是偶数个,所以考虑将它们两两配对。设 \(b_{i},b_{j}\) 都是 \(1\),那么将它们都变为 \(0\) 的代价有三种情况:
- \(\lvert i-j\rvert\) 是奇质数,需要 \(1\) 的代价。
- \(\lvert i-j\rvert\) 是偶数,需要 \(2\) 的代价。证明是:当 \(4<x\leq 10^7\) 且 \(x\) 是偶数时,\(x\) 是两个奇质数之和。当 \(x\) 没有上限时,这就是哥德巴赫猜想。当 \(x=2\) 时,\(x=5-3\);当 \(x=4\) 时,\(x=7-3\),也满足条件。
- \(\lvert i-j\lvert\) 是奇合数或 \(1\) 时,需要 \(3\) 的代价。证明是:当 \(x>7\) 且 \(x\) 是质数时,\(x\) 时三个奇质数之和。这是弱哥德巴赫猜想,已经被证明。当 \(x=1\) 时,\(x=3+3-5\),也满足条件。
我们设 \(b\) 数组上有 \(odd\) 个 \(1\) 的位置是奇数,\(even\) 个 \(1\) 的位置是偶数。设最多能匹配 \(k\) 对 \(\lvert i-j\rvert\) 使得 \(\lvert i-j\rvert\) 是奇质数,那么答案为 \(b+(odd-b)/2\times 2+(even-b)/2\times 2+((odd-b)\%2)\times 3\)。
那么对满足 \(\lvert i-j\rvert\) 是奇质数的 \(i,j\) 之间建边。我们令 \(i\) 是奇数时是左部点,\(i\) 是偶数时是右部点,那么这就是个二分图最大匹配。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=410, M=10000010, INF=1e9;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,m,od,ev,a[N],b[N];
int book[M+10],pri[M/10+5],cnt;
inline void Init()
{
for(ri int i=2;i<=M;i++)
{
if(!book[i]) pri[++cnt]=i;
for(ri int j=1;j<=cnt&&i*pri[j]<=M;j++)
{
book[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
}
int S,T,dis[N],Ans;
int head[N],maxE,cur[N]; struct Edge { int nxt,to,rdis; }e[N*N*2];
inline void Add(int u,int v,int w) { e[maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; e[maxE].rdis=w; maxE++; }
inline bool BFS()
{
memset(dis,-1,sizeof(dis));
queue<int> Q;
dis[S]=0, Q.push(S);
while(!Q.empty())
{
int x=Q.front(); Q.pop();
for(ri int i=head[x];~i;i=e[i].nxt)
{
int v=e[i].to;
if(dis[v]==-1&&e[i].rdis>0)
{
dis[v]=dis[x]+1;
Q.push(v);
}
}
}
return ~dis[T];
}
int DFS(int x,int pro)
{
if(x==T) return pro;
int res,p;
res=p=0;
for(int &i=cur[x];~i;i=e[i].nxt)
{
int v=e[i].to;
if(dis[v]==dis[x]+1&&e[i].rdis>0)
{
p=DFS(v,min(pro,e[i].rdis));
if(!p) continue;
pro-=p, res+=p;
e[i].rdis-=p, e[i^1].rdis+=p;
if(!pro) break;
}
}
if(!res) dis[x]=-1;
return res;
}
signed main()
{
Init(), memset(head,-1,sizeof(head));
n=read();
for(ri int i=1;i<=n;i++) a[i]=read();
b[m=1]=a[1];
for(ri int i=2;i<=n;i++) if(a[i]-a[i-1]>1) b[++m]=a[i-1]+1, b[++m]=a[i];
b[++m]=a[n]+1, T=m+1;
for(ri int i=1;i<=m;i++)
{
if(b[i]&1) od++;
else ev++;
}
for(ri int i=1;i<=m;i++)
for(ri int j=i+1;j<=m;j++)
if(b[j]-b[i]>2 && !book[b[j]-b[i]])
{
if(b[i]&1) Add(i,j,1), Add(j,i,0);
else Add(j,i,1), Add(i,j,0);
}
for(ri int i=1;i<=m;i++)
{
if(b[i]&1) Add(S,i,1), Add(i,S,0);
else Add(i,T,1), Add(T,i,0);
}
while(BFS())
{
for(ri int i=0;i<=T;i++) cur[i]=head[i];
Ans+=DFS(S,INF);
}
printf("%d\n",Ans+(od-Ans)/2*2+(ev-Ans)/2*2+((od-Ans)&1)*3);
return 0;
}