AT2689 [ARC080D] Prime Flip
生活随笔
收集整理的這篇文章主要介紹了
AT2689 [ARC080D] Prime Flip
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
簡要題解如下:
區間修改問題,使用差分轉化為單點問題。
問題變成,一開始有 (2n) 個點為 (1),每次操作可以選擇 (r - l) 為奇質數的兩個點 (l, r) 使其 ^ (1)。
根據哥德巴赫猜想可以發現,若 (r - l) 為奇質數顯然一次即可,若 (r - l) 為偶數則需兩次,若 (r - l) 為奇數則需三次。
近一步可以發現,若想消去兩個點 (l, r) 則涉及其他點是可以通過調整使得直接消去兩個點的。
更近一步可以發現,將所有點按照奇偶分類,顯然若消去奇偶性相同的兩個數只能 (2) 次,那么首先將差是奇質數的點一起消去肯定是最優的。
因為差是奇質數的點必然一個為偶數一個為奇數構成二分圖,于是可以使用匈牙利或網絡流解決二分圖最大匹配問題。
剩下的肯定要同集合內部按照 (2) 次消去,最后若還剩一個元素才使用 (3) 次的方法。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define Next(i, u) for (int i = cur[u]; i; i = e[i].next)
const int N = 2e4 + 5;
const int M = 1e7 + 5;
struct edge { int v, next, w;} e[N << 1];
int n, s, t, F, ans, cnt, tot = 1, ton[2], a[N], h[N], d[M];
namespace PR {
bool iprime[M]; int tot, prime[M];
void sieve(int L) {
iprime[1] = 1;
rep(i, 2, L) {
if(!iprime[i]) prime[++tot] = i;
for (int j = 1; j <= tot && i * prime[j] <= L; ++j) {
iprime[i * prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
}
}
namespace FL {
bool book[N]; int dep[N], cur[N];
bool bfs(int s, int t) {
rep(i, s, t) cur[i] = h[i], dep[i] = -t;
queue <int> Q;
dep[s] = 1, Q.push(s);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
Next(i, u) {
int v = e[i].v; if(!e[i].w || dep[v] > 0) continue;
dep[v] = dep[u] + 1, Q.push(v);
}
}
return dep[t] > 0;
}
int dfs(int u, int lim) {
if(u == t) return lim;
int flow = 0, rflow = 0; book[u] = true;
Next(i, u) {
int v = e[i].v; cur[u] = i;
if(!book[v] && dep[v] == dep[u] + 1 && e[i].w && (rflow = dfs(v, min(e[i].w, lim)))) {
flow += rflow, lim -= rflow, e[i].w -= rflow, e[i ^ 1].w += rflow;
if(!lim) break;
}
}
book[u] = false; return flow;
}
}
void add(int u, int v, int w) {
e[++tot].v = v, e[tot].w = w, e[tot].next = h[u], h[u] = tot;
e[++tot].v = u, e[tot].w = 0, e[tot].next = h[v], h[v] = tot;
}
int main () {
cin >> n;
rep(i, 1, n) cin >> a[i], d[a[i]] ^= 1, d[a[i] + 1] ^= 1;
PR :: sieve(M - 1);
s = cnt = 1;
rep(i, 1, M - 1) if(d[i]) a[++cnt] = i, ++ton[i & 1];
t = ++cnt;
rep(i, 2, cnt - 1) {
if(a[i] & 1) add(s, i, 1);
else add(i, t, 1);
}
rep(i, 2, cnt - 1) if(a[i] & 1) {
rep(j, 2, cnt - 1) if(!(a[j] & 1) && !(PR :: iprime[abs(a[j] - a[i])])) add(i, j, 1);
}
while (FL :: bfs(s, t)) ans += FL :: dfs(s, cnt);
if((ton[0] - ans) & 1) F = 1;
ans += 2 * ((ton[0] - ans) / 2 + (ton[1] - ans) / 2);
ans += F * 3;
printf("%d", ans);
return 0;
}
首先區間修改差分轉單點是非常重要的,可以減少有效修改點數,方便于觀察問題。
對于某個數能被質數 / 奇質數組成的問題,一定要敏銳地想到 哥德巴赫猜想
總結
以上是生活随笔為你收集整理的AT2689 [ARC080D] Prime Flip的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: <转>植物大战僵尸 基址
- 下一篇: 网申浦发信用卡怎么激活?首卡需到网点激活