【二分图】【质数】【转换】[ARC080F] Prime Flip
神。
要把所有硬币翻转成反面,也就是说要把所有 通过某种方式翻转。定义 。会发现,假如翻转 ,其实是在翻转 ,题目要求 为奇素数。这种差分是套路。
现在问题转换为:用最少的翻转次数,使所有 相同。
-
我们可以直接翻转 为奇素数的情况。
-
对于是偶数的情况。因为哥德巴赫猜想“任意大于 的偶数都能被表示为两个奇素数之和”在题目范围内是正确的,即 。这样一来,只要翻转 就好了。稍微尝试一下,发现 2 可以表示为 ,即翻转 。 同理可得。总而言之,偶数通过两次翻转消除。
-
对于是奇数并且不是质数的情况。因为
哥德巴赫猜想(还真是)的时候,只要将上面的结论 就可以得到了... 可以手动枚举一下。总而言之,奇数但不素数通过两次翻转消除。
根据贪心,按照 的顺序消除。因为奇数是 奇偶性不同的情况,将所有奇,偶数分类跑二分图最大匹配。偶数是 奇偶性相同的情况,直接排除情况 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;
}

浙公网安备 33010602011771号