[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;
}
posted @ 2021-02-23 14:19  zkdxl  阅读(62)  评论(0编辑  收藏  举报