AT_arc080_d Prime Flip题解
首先起手差分,问题转换成每次可以把两个点 \(i,j(i<j,j-i\in prime)\) 状态翻转,考虑对于如果这有两个点(\(x,y\))的情况:
- \(y-x \in prime\)
直接一次操作即可。 - \(2\mid y-x\)
由哥德巴赫猜想可知,当 \(y-x\ge 6\) 的时候,已从存在一个 \(i\) 满足可以先操作 \(x,i\) 再操作 \(i,y\),而当 \(y-x=2\) 时,先操作 \(x,x+5\) 再操作 \(x+5,x+2\),当 \(y-x=4\) 时,先操作 \(x,x+11\),再操作 \(x+11,x+4\) 即可,两次。 - \(y-x\) 是奇合数
首先,显然不可能只操作两次,然后注意到当 \(y-x\ge 9\) 的时候,先操作 \(x,x+3\),转化成第二种情况,当 \(y-x=1\) 的时候,直接操作 \(x,x+3\)、\(x+3,x+6\)、\(x+1,x+6\) 即可,三次。
然后考虑贪心,先优先使用第一种操作,二分图最大匹配(左部点为奇数,右部点为偶数),对于剩下的,考虑贪心的使用二操作,注意到之后剩下的一定最多使用一次三操作即可,因为点数是偶数。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 550, M = N * N, inf = 0x3f3f3f3f, K = 10001000;
struct Dinic{
int n, S, T;
struct Edge{
int nxt, to, r, fl;
Edge() {}
Edge(int _nxt, int _to, int _r)
: nxt(_nxt), to(_to), r(_r), fl(0) {}
} e[M];
int h[N], cnt, nw[N];
void add(int u, int v, int c) {
e[cnt] = Edge(h[u], v, c), h[u] = cnt++;
e[cnt] = Edge(h[v], u, 0), h[v] = cnt++;
return;
}
void init(int _n) {
n = _n, cnt = 0, S = n + 1, T = n + 2;
memset(h, -1, sizeof h);
return;
}
int d[N];
bool bfs() {
queue<int> q;
for (int i = 1; i <= n; ++i) d[i] = 0;
d[S] = 1, d[T] = 0;
q.push(S);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = h[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (d[v] || e[i].r <= e[i].fl) continue;
d[v] = d[u] + 1, q.push(v);
}
}
return (d[T] > 0);
}
int dfs(int u, int lim) {
if (u == T || lim == 0) return lim;
int ret = 0;
for (int i = nw[u]; ~i; i = nw[u]) {
int v = e[i].to, Limie;
if (d[v] != d[u] + 1) {
nw[u] = e[i].nxt;
continue;
}
Limie = dfs(v, min(lim - ret, e[i].r - e[i].fl));
ret += Limie, e[i].fl += Limie, e[i ^ 1].fl -= Limie;
if (ret == lim) break;
nw[u] = e[i].nxt;
}
return ret;
}
int dinic() {
for (int i = 0; i < cnt; ++i) e[i].fl = 0;
int res = 0;
while (bfs()) {
for (int i = 1; i <= n; ++i) nw[i] = h[i];
nw[S] = h[S], nw[T] = h[T];
res += dfs(S, inf);
}
return res;
}
} zq;
int n;
bool b[K];
int id[K], ct;
bool ck(int x) {
if (x <= 2) return 0;
for (int i = 2; i * i <= x; ++i) if (x % i == 0) return 0;
return 1;
}
vector<int> lft, rgt;
int ln, rn;
int main() {
scanf("%d", &n);
for (int i = 1, x; i <= n; ++i) scanf("%d", &x), b[x] ^= 1, b[x + 1] ^= 1;
for (int i = 1; i < K; ++i) if (b[i]) {
(i & 1 ? lft : rgt).emplace_back(i), id[i] = ++ct;
}
ln = lft.size(), rn = rgt.size();
zq.init(ln + rn);
for (int l : lft) for (int r : rgt) if (ck(max(l, r) - min(l, r))) zq.add(id[l], id[r], 1);
for (int l : lft) zq.add(zq.S, id[l], 1);
for (int r : rgt) zq.add(id[r], zq.T, 1);
int ans = zq.dinic(), ret = ans; ln -= ans, rn -= ans;
ret += ln / 2 * 2 + rn / 2 * 2, ln %= 2, rn %= 2;
assert(ln == rn);
ret += 3 * ln;
printf("%d\n", ret);
return 0;
}

浙公网安备 33010602011771号