AT_abc263_g [ABC263G] Erasing Prime Pairs 题解

有趣的网络流。

首先,除了 22,所有质数都是奇数,所以只能被表示成两个奇偶性不同的数的和。所以我们先抛开 22 不谈。

如果抛开 22,意味着原序列没有 11。若是这样,我们可以直接最大流解决,具体是这样:

  • 考虑对于 ai+aja_i+a_j 为质数且 aia_i 是奇数的数对 (i,j)(i,j),连边 iji \rightarrow j,容量为 ++\infty

  • 对于 aia_i 是奇数的 ii,连 SiS \rightarrow i,容量为 bib_i,表示只有 iiaia_i

  • 对于 aia_i 是偶数,连 iTi \rightarrow T,容量为 bib_i,表示只有 iiaia_i

  • STS \rightarrow T 最大流 pp,即为答案。

但是我们发现,1+1=21+1=2,并不是奇数和偶数之和。这是本题的难点。

我们对于上述方案,求出最大流后,令 S1S \rightarrow 1 的容量为 cc,实际流量为 ff。那么我们可以用 1+1=21+1=2 得到质数 cf2\lfloor \frac{c-f}{2} \rfloor 个。为了最大化 p+cf2p + \lfloor \frac{c-f}{2} \rfloor,我们需要在最大化 pp 的前提下最小化 ff

若我们没有最大化 pp,那么相当于至少少获得了一个质数,即少用了两个数,而这两个数不可能都是 11,所以 p+cf2p + \lfloor \frac{c-f}{2} \rfloor 不会更优。所以我们应该先最大化 pp

于是转化成费用流模型,S1S \rightarrow 1 的边费用为 11,其余费用为 00,最小费用最大流即可。

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 5e4 + 5, M = 2e7 + 5;

int e[N], h[N], c[N], ne[N], idx, a[N], b[N], n, cs[N];
int prime[M], cnt, S = 0, T, ret;
bool np[M], isin[N];

void Init()
{
	np[1] = 1;
	for (int i = 2; i < M; i++)
	{
		if (!np[i])
		{
			prime[++cnt] = i;
		}
		for (int j = 1; j <= cnt && 1LL * i * prime[j] < M; j++)
		{
			np[1LL * i * prime[j]] = 1;
			if (i % prime[j] == 0) break;
		}
	}
}

inline void add(int u, int v, int w, int cc)
{
	e[idx] = v, c[idx] = w, ne[idx] = h[u], cs[idx] = cc, h[u] = idx++;
	e[idx] = u, c[idx] = 0, ne[idx] = h[v], cs[idx] = -cc, h[v] = idx++;
}

int dis[N], cur[N];

inline bool bfs()
{
	for (int i = 0; i <= T; i++) dis[i] = 1e18, cur[i] = -1;
	queue<int> q;
	q.push(S);
	dis[S] = 0, cur[S] = h[S];
	while (q.size())
	{
		int u = q.front();
		q.pop();
		isin[u] = 0;
		for (int i = h[u]; ~i; i = ne[i])
		{
			int j = e[i];
			if (c[i] > 0 && dis[j] > dis[u] + cs[i])
			{
				dis[j] = dis[u] + cs[i];
				cur[j] = h[j];
				if (!isin[j]) q.push(j), isin[j] = 1;
			} 
		} 
	}
	return (dis[T] != 1e18);
}

inline int dfs(int u, int lim)
{
	if (u == T) return lim;
	isin[u] = 1;
	int res = 0;
	for (int i = cur[u]; ~i && res < lim; i = ne[i])
	{
		cur[u] = i;
		int j = e[i];
		if (!isin[j] && dis[j] == dis[u] + cs[i] && c[i] > 0)
		{
			int p = dfs(j, min(lim - res, c[i]));
			ret += p * cs[i];
			res += p;
			c[i] -= p;
			c[i ^ 1] += p;
		}
	}
	isin[u] = 0;
	return res;
}

inline int dinic()
{
	int sum = 0, p;
	while (bfs())
	{
		while (p = dfs(S, INT_MAX)) sum += p;
	}
	return sum;
} 

signed main()
{
	memset(h, -1, sizeof h);
	Init();
	scanf("%lld", &n);
	int p = 0;
	for (int i = 1; i <= n; i++) 
	{
		scanf("%lld%lld", &a[i], &b[i]);
		if (a[i] == 1) p = b[i];
	}
	T = n + 1;
	for (int i = 1; i <= n; i++)
	{
		if (a[i] % 2 == 0) continue;
		for (int j = 1; j <= n; j++)
		{
			if (i != j && !np[a[i] + a[j]])
			{
				add(i, j, INT_MAX, 0);
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (a[i] & 1) add(S, i, b[i], (a[i] == 1));
		else add(i, T, b[i], 0);
	}
	int res = dinic();
	printf("%lld\n", res + (p - ret) / 2);
	return 0;
}
posted @   HappyBobb  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示