\(a_i\) 和質數看著並沒有很特殊,於是一些貪心或者是 DP 的大抵是做不了的。
於是一個想法是對於 \(a_i + a_j = p(p\in \mathbf{P})\) 的 \((i, j)\) 連邊,然後跑網路流。
但是需要確定的是這個建出來的圖能不能拿來跑。
能夠發現的是對 \(p\in \mathbf{P}, p\not = 2\),都滿足 \(p\bmod 2 = 1\),這說明這些和為 \(p\) 的連邊都是由 \(a_i\bmod 2 = 0\) 和 \(a_i\bmod 2 = 1\) 連上的,那麼顯然為一個二分圖。
於是就可以建圖了。
對於 \(a_i\bmod 2 = 1\),連邊 \((\operatorname{S}, i, b_i)\);對於 \(a_i\bmod 2 = 0\),連邊 \((i, \operatorname{T}, b_i)\)。
對於 \(a_i\bmod 2 = 1, a_j\bmod 2 = 0, a_i + a_j= p(p\in \mathbf{P})\),連邊 \((i, j, \operatorname{inf})\)。
注意到其實還有 \(p = 2\) 的特殊情況。
但時發現此時只有可能是 \((1, 1)\)。
於是可以最後跑完看下 \(1\) 還有多少流量沒用,就可以計算了(因為用 \(1\) 個 \(1\) 顯然比 \(2\) 個 \(1\) 優)。
但是一個問題是如果直接最大流可能會導致沒有先去配對 \((a_i, a_j)(a_i\not = 1)\) 而是去配對了 \((1, a_j)\)。
這可能導致 \(1\) 剩餘流量變少而使答案變小。
於是可以先不把 \(1\) 加入圖中跑一次最大流,此時就已經保證了非 \(1\) 的奇數已經儘量匹配完了。
然後再加入 \(1\),再跑一次最大流,讓 \(1\) 去匹配。
最後再統計流量即可。
時間複雜度 \(\mathcal{O}(V + \operatorname{flow}(n, n^2))\)。
#include<bits/stdc++.h>
using ll = long long;
constexpr ll inf = 1e18;
int N, S, T;
namespace flow {
static const int maxn = 1e2 + 10, maxm = 2e4 + 10;
ll val[maxm * 2];
int to[maxm * 2], nxt[maxm * 2], fir[maxn], tot = 1;
inline void add(int x, int y, ll w, bool f = 1) {
to[++tot] = y, val[tot] = w, nxt[tot] = fir[x], fir[x] = tot;
if (f) add(y, x, 0, 0);
}
int hd[maxn], dep[maxn];
inline bool bfs() {
for (int i = 1; i <= N; i++)
hd[i] = fir[i], dep[i] = -1;
dep[S] = 0;
std::queue<int> Q; Q.push(S);
while (! Q.empty()) {
int u = Q.front(); Q.pop();
if (u == T) return true;
for (int i = hd[u]; i; i = nxt[i])
if (dep[to[i]] == -1 && val[i])
dep[to[i]] = dep[u] + 1, Q.push(to[i]);
}
return false;
}
inline ll dfs(int u, ll fl) {
if (u == T) {
return fl;
}
ll ud = 0;
for (int &i = hd[u]; i; i = nxt[i])
if (dep[u] + 1 == dep[to[i]] && val[i]) {
ll k = dfs(to[i], std::min(fl - ud, val[i]));
if (! k) dep[to[i]] = -1;
ud += k, val[i] -= k, val[i ^ 1] += k;
if (ud == fl)
return fl;
}
return ud;
}
inline ll Dinic() {
ll ans = 0, f;
while (bfs()) {
while ((f = dfs(S, inf)) > 0) {
ans += f;
}
}
return ans;
}
};
const int maxn = 1e2 + 10, maxV = 2e7 + 10, V = 2e7;
std::bitset<maxV> f;
int n;
int a[maxn], b[maxn];
int main() {
for (int i = 2; i <= V; i++) {
if (! f[i]) {
for (int j = i + i; j <= V; j += i) {
f[j] = 1;
}
}
}
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i], &b[i]);
}
S = n + 1, N = T = n + 2;
for (int i = 1; i <= n; i++) {
if (a[i] == 1) continue;
if (a[i] & 1) {
flow::add(S, i, b[i]);
} else {
flow::add(i, T, b[i]);
}
}
for (int i = 1; i <= n; i++) {
if (a[i] == 1) continue;
if (a[i] & 1) {
for (int j = 1; j <= n; j++) {
if (j != i && ! f[a[i] + a[j]]) {
flow::add(i, j, inf);
}
}
}
}
ll ans = flow::Dinic();
for (int i = 1; i <= n; i++) {
if (a[i] == 1) {
for (int j = 1; j <= n; j++) {
if (j != i && ! f[a[j] + 1]) {
flow::add(i, j, inf);
}
}
flow::add(S, i, b[i]);
ans += flow::Dinic();
ans += flow::val[flow::tot - 1] / 2;
}
}
printf("%lld\n", ans);
return 0;
}