【二分图】【质数】【转换】[ARC080F] Prime Flip

神。

要把所有硬币翻转成反面,也就是说要把所有 aia_i 通过某种方式翻转。定义 bi=[aiai1]b_i = [a_i \not = a_{i-1}]。会发现,假如翻转 aiaj1a_i\sim a_{j-1},其实是在翻转 bi,bjb_i,b_{j},题目要求 jij-i 为奇素数。这种差分是套路。

现在问题转换为:用最少的翻转次数,使所有 bib_i 相同。

  1. 我们可以直接翻转 jij-i 为奇素数的情况。

  2. 对于是偶数的情况。因为哥德巴赫猜想“任意大于 44 的偶数都能被表示为两个奇素数之和”在题目范围内是正确的,即 len=p+qlen = p+q。这样一来,只要翻转 bi,bi+p,bi+p,bi+p+qb_i,b_{i+p},b_{i+p},b_{i+p+q} 就好了。稍微尝试一下,发现 2 可以表示为 2+5=72+5=7,即翻转 bi,bi+7,bi+2,bi+7b_i,b_{i+7},b_{i+2},b_{i+7}44 同理可得。总而言之,偶数通过两次翻转消除。

  3. 对于是奇数并且不是质数的情况。因为 哥德巴赫猜想(还真是) ij>3i-j > 3 的时候,只要将上面的结论 +3+ 3 就可以得到了...1,31,3 可以手动枚举一下。总而言之,奇数但不素数通过两次翻转消除。

根据贪心,按照 1,2,31,2,3 的顺序消除。因为奇数是 j,ij,i 奇偶性不同的情况,将所有奇,偶数分类跑二分图最大匹配。偶数是 j,ij,i 奇偶性相同的情况,直接排除情况 1 计算。还有两种剩下的跑第三种。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int n,a[N],b[N];

int tag,vis[N],c[N];
vector<int>e[N];
bool dfs(int u) {
	if(vis[u]==tag) return false;
	vis[u]=tag;
	for(int v:e[u]) {
		if(!c[v]||dfs(c[v])) {
			c[v]=u; return true;
		}
	}
	return false;
}

bool ok(int x) {
	if(x <= 2) return 0;
	for(int i=2;i*i<=x;i++)
		if(x % i == 0) return 0;
	return 1;
}
int main() {
	cin>>n;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
	}
	a[0] = -1;
	int idx = 0;
	for(int i=1;i<=n;i++) {
		if(a[i] - a[i-1] > 1) {
			if(i != 1)b[++idx] = a[i-1]+1;
			b[++idx] = a[i];
		}
	}
	b[++idx] = a[n] + 1;
	n = idx;
	for(int i=1;i<=n;i++) {
		if(b[i] % 2) {
			for(int j=1;j<=n;j++) {
				if(ok(abs(b[i]-b[j]))) e[i].push_back(j);
			}
		}
	}
	int pp = 0, os = 0;
	for(int i=1;i<=n;i++) {
		os += b[i] % 2;
		tag ++;
		if(dfs(i)) pp ++;
	}
	cout<<pp + (os - pp) /2 *2 + (n - os - pp) / 2 * 2 + ((os - pp) % 2) * 3 ;
	return 0;
}
posted @ 2024-07-16 19:14  cjrqwq  阅读(10)  评论(0)    收藏  举报  来源