Maximize Mex

题面

在一所学校里有 $n$ 名学生和 $m$ 个社团,社团被编号为 $1$ ~ $m$ 。第 $i$ 个学生有一个能力值 $p_i$ ,且属于社团 $c_i$ (每个学生恰好属于一个社团) 。

学校将要举行一个为期 $d$ 天的活动,每天学校要举行一场程序设计比赛 —— 校长将会从每个社团中选出一个人(如果某个社团没有人,就不选)组成一个队,令队里的学生的能力值的集合为 $S$ ,则该队的总能力值 $mex(S)$

$mex(S)$ 表示 $S$ 中没有出现的最小的非负整数。例如:

$mex(\{0,1,3,4\})=2;mex(\{1,2,3\})=0$

但是由于学业繁忙,第 $i$ 天时,第 $k_i$ 个学生会离开社团(在校长选这一天参加比赛的学生之前)。

校长希望知道对于活动的每一天,他可能选出的队伍的总能力值最大是多少。

题解

二分图模型维护 mex。

代码

const int N = 5010;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, m;
	int a[N], b[N], c[N];
	bool used[N];
	int p[N], ans[N];
	int head[N], tot;
	struct Edge {int to, nxt;} e[N];
	void add_edge(int u, int v) { e[++tot] = (Edge) {v, head[u]}, head[u] = tot;}
	bool find(int u) {
		if (used[u]) return 0;
		used[u] = 1;
		for (int i = head[u]; i; i = e[i].nxt) 
			if (p[e[i].to] == -1 || find(p[e[i].to])) {
				p[e[i].to] = u; return 1;
			}
		return 0;
	}
	int main () {
		memset (p, -1, sizeof p);
		n = Read(), m = Read();
		for (int i = 1; i <= n; i++) a[i] = Read();
		for (int i = 1; i <= n; i++) b[i] = Read();
		m = Read();
		for (int i = 1; i <= m; i++) used[c[i] = Read()] = 1;
		for (int i = 1; i <= n; i++) if (!used[i]) add_edge(a[i], b[i]);
		int mex = 0;
		for (int i = m; i; --i) {
			memset (used, 0, sizeof used);
			for (; find(mex); mex++, memset (used, 0, sizeof used));
			add_edge(a[c[i]], b[c[i]]); ans[i] = mex;
		}
		for (int i = 1; i <= m; i++) printf ("%d\n", ans[i]);
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2024-02-29 18:32:31
Tags