[ARC080D] Prime Flip

前言

ARC080D

题目

洛谷

AT

讲解

区间翻转考虑差分,差分后1的数量一定为偶数。

然后考虑将差分后的1分为奇数和偶数,组成天然的二分图。

此时我们有三种操作:

1.奇质数,代价为\(1\)

2.偶数,代价为\(2\),原理为哥德巴赫猜想。(特例:2=5-3,4=7-3)

3.奇合数,代价为\(3\),原理为奇质数3+操作2。

考虑奇偶相减为奇数,所以我们可以对操作1跑二分图匹配,剩下的尽量用操作2,实在不行用操作3。

tip:判断奇质数不用线性筛会快很多。

代码

大部分是dinic的板子

int head[MAXN],tot = 1;
struct node
{
	int v,w,nxt;
}e[MAXN * MAXN];
void Add_Edge(int x,int y,int z)
{
	e[++tot].v = y;
	e[tot].w = z;
	e[tot].nxt = head[x];
	head[x] = tot;
}
void Add_Double_Edge(int x,int y,int z)
{
	Add_Edge(x,y,z);
	Add_Edge(y,x,0);
}

int dis[MAXN],q[MAXN];
bool bfs()
{
	for(int i = 1;i <= N;++ i) dis[i] = -1;
	int l,r; dis[q[l = r = 1] = S] = 0;
	while(l <= r)
	{
		int p = q[l++];
		for(int i = head[p]; i ;i = e[i].nxt)
			if(e[i].w > 0 && dis[e[i].v] == -1)
				dis[e[i].v] = dis[p] + 1,q[++r] = e[i].v;
	}
	return dis[T] != -1;
}
int cur[MAXN];
int dfs(int x,int flow)
{
	if(x == T) return flow;
	int ret = 0;
	for(int &i = cur[x]; i ;i = e[i].nxt)
		if(e[i].w > 0 && dis[x] + 1 == dis[e[i].v])
		{
			int dz = dfs(e[i].v,Min(e[i].w,flow-ret));
			e[i].w -= dz; e[i^1].w += dz;
			if((ret += dz) == flow) break;
		}
	if(!ret) dis[x] = -1;
	return ret;
}
int dinic() 
{
	int ret = 0;
	while(bfs())
	{
		for(int i = 1;i <= N;++ i) cur[i] = head[i];
		ret += dfs(S,INF);
	}
	return ret;
}

int l[MAXN],r[MAXN],ltot,rtot;
void Add(int x)
{
	if(x & 1) l[++ltot] = x;
	else r[++rtot] = x;
}

bool check(int x)
{
	if(x <= 2) return 0;
	if(!(x & 1)) return 0;
	for(int i = 3;i * i <= x;++ i)
		if(x % i == 0) return 0;
	return 1;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	for(int i = 1;i <= n;++ i) a[i] = Read();
	Add(a[1]);
	for(int i = 2;i <= n;++ i)
		if(a[i] > a[i-1]+1)
		{
			Add(a[i-1]+1);
			Add(a[i]);
		}
	Add(a[n]+1);
	S = ltot + rtot + 1; N = T = S + 1; 
	for(int i = 1;i <= ltot;++ i) Add_Double_Edge(S,i,1);
	for(int i = 1;i <= rtot;++ i) Add_Double_Edge(i+ltot,T,1);
	for(int i = 1;i <= ltot;++ i)
		for(int j = 1;j <= rtot;++ j)
			if(check(Abs(l[i]-r[j])))
				Add_Double_Edge(i,j+ltot,1);
	int sum = dinic();
	Put(sum + (ltot - sum) / 2 * 2 + (rtot - sum) / 2 * 2 + ((ltot - sum) & 1) * 3);//ltot与rtot奇偶性一定相同,所以只需要用ltot-sum判断
	return 0;
}
posted @ 2021-02-17 18:47  皮皮刘  阅读(36)  评论(0编辑  收藏  举报