LY1107 [ 20230225 CQYC模拟赛 T2 ] 圣诞决斗

题意

给定一棵大小为 \(n\) 的树。

有两个人,每个点属于其中某一个人。

每轮选择一个度数为 \(1\) 的点删掉,设最后取得点的主人获胜。

问谁会获胜。

Sol

博弈分讨萌萌题。

首先这道题直接做肯定不好做。

考虑从特殊性质出发。

首先,对于链来说。不难想到要对于 \(n\) 的奇偶性分讨。

注意到当 \(n\) 为偶数时,先手可以控制最后的点在中间两点之中的哪个点。

反之,若中间两点都不是先手的点,后手也可以控制最后的点在中间两点之中。

所以,中间两点一点为先手则先手获胜,反之后手获胜。

\(n\) 为奇数时,不难发现先手选择一点后就变为了偶数后手的情况。

所以当中间点为后手时,就变为了偶数先手的情况,也就是后手获胜。

先手获胜当且仅当中间三个点,其中有两个点为先手,并且中间点也为先手。

考虑菊花图。

菊花图是 \(trivial\) 的,不难发现,两个人的最优方案都是优先选择对方的节点。

所有考虑除了中心以外谁的节点更多,谁就获胜。

注意到链和菊花的答案都和 中心 有关。

这启发我们朝树的重心思考。

不难发现,树的重心一定是最后选择的节点。

考虑对于 \(n\) 的奇偶分讨。

\(n\) 为奇数 时:

  • 类似于链,重心为后手点,则后手必胜。
  • 类似于菊花,重心为先手点,考虑将所有儿子的 \(siz\) 加起来。

\(n\) 为偶数 时:

  • 类似于链,如果有一个重心属于先手,先手必胜,若两个重心均为后手点,则后手必胜。
  • 类似于菊花,重心唯一且属于后手,和 \(n\) 为奇数重心为先手点的情况相同。

做完了。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <vector>
#include <cassert>
#define pii pair <int, int>
using namespace std;
#ifdef ONLINE_JUDGE

/* #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) */
/* char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; */

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') flg -= -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		p = p * 10 + c - '0';
		c = getchar();
	}
	return p * flg;
}
void write(int x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9) {
		write(x / 10);
	}
	putchar(x % 10 + '0');
}
#define fi first
#define se second

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

namespace G {

array <int, N> fir;
array <int, M> nex, to;
int cnt = 1;

void add(int x, int y) {
	cnt++;
	nex[cnt] = fir[x];
	to[cnt] = y;
	fir[x] = cnt;
}

}

array <int, N> fa, siz;
vector <pii> rt;

void dfs(int x, int n) {
	int tp = 0;
	siz[x] = 1;
	for (int i = G::fir[x]; i; i = G::nex[i]) {
		if (G::to[i] == fa[x]) continue;
		fa[G::to[i]] = x;
		dfs(G::to[i], n);
		siz[x] += siz[G::to[i]];
		tp = max(tp, siz[G::to[i]]);
	}
	tp = max(tp, n - siz[x]);
	if (tp < rt.back().fi) rt.clear(), rt.push_back(make_pair(tp, x));
	else if (tp == rt.back().fi) rt.push_back(make_pair(tp, x));
}


char strbuf[N];

void calc(int n) {
	fa.fill(0);
	dfs(rt.front().se, n);
	int tp1(0), tp2(0);
	for (int i = G::fir[rt.front().se]; i; i = G::nex[i])
		strbuf[G::to[i]] == 'C' ? tp1 += siz[G::to[i]] : tp2 += siz[G::to[i]];
	if (tp1 >= tp2) puts("Clash");
	else puts("Royale");
}

void solve() {
	int n = read();
	scanf("%s", strbuf + 1);
	G::cnt = 1, G::fir.fill(0);
	for (int i = 2; i <= n; i++) {
		int x = read(), y = read();
		G::add(x, y), G::add(y, x);
	}
	rt.push_back(make_pair(n + 1, 0));
	fa.fill(0);
	dfs(1, n);
	bool flg1 = n & 1, flg2 = rt.size() == 1, flg3 = strbuf[rt.front().se] == 'C', flg4 = strbuf[rt.back().se] == 'C';
	if (flg1 && flg3) calc(n);
	if (flg1 && !flg3) puts("Royale");
	if (!flg1 && (flg3 || flg4)) puts("Clash");
	if (!flg1 && !flg2 && !flg3 && !flg4) puts("Royale");
	if (!flg1 && flg2 && !flg3) calc(n);

}

int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	int T = read();
	while (T--) solve();
	return 0;
}
posted @ 2024-01-03 11:48  cxqghzj  阅读(6)  评论(0编辑  收藏  举报