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;
}
posted @ 2024-10-14 16:01  yaoyanfeng  阅读(9)  评论(0)    收藏  举报