Codeforces Round 821 (Div. 2) B. Rule of League

发布时间 2023-09-09 22:22:17作者: zsxuan

\(n\) 名选手参加一场比赛,编号为 \(1 \sim n\) 。规则为:

  • 选手 \(1\) 和选手 \(2\) 比赛
  • \(1\) 轮胜者胜者与选手 \(3\) 比赛;
  • \(2\) 轮胜者与选手 \(4\) 比赛
  • \(\cdots\)
  • \(n - 2\) 轮胜者与选手 \(n\) 比赛。

若能构造一组比赛结果 \(b\)\(b_i\) 代表第 \(i\) 轮获胜的选手编号,输出任意一组。且只知道以下信息:

  • 任一参赛选手要么胜利 \(x\) 轮要么胜利 \(y\) 轮。

诈骗题,\(x\) \(y\) 一定有且仅有是 \(0\)

观察一:每轮一输一赢,则 \(\sum_{i}^{n} win_{i} = \sum_{i}^{n} lose_{i}\)

观察二:有 \(n - 1\) 个参赛选手会输一次,则 \(\sum_{i}^{n} lose_{i} = n - 1\) ,即 \(\sum_{i}^{n} win_{i} = n - 1\) 。根据鸽巢原理,(至少)存在一个人赢不了,保证 \(min(x, y) = 0\)

观察三:显然(至少)存在一个人能赢,保证 \(max(x, y) > 0\)

观察四:共 \(n - 1\) 轮,每 \(max(x, y)\) 轮分为一组。

观察五:每 \(max(x, y)\) 轮中,只有该组第一轮的俩人之一赢 \(max(x, y)\) 轮,其他人全输。

于是问题解决:

\(min(x, y) \neq 0\) 或者 \(max(x, y) \nmid n - 1\) 则无解。

  • 判断 \(x \mid y\) 时若用 \(y \% x\) 判断,当 \(x = 0\) 时出现运算错误。可用 \(gcd(x, y)\) 判断,若满足则 \(g = x\)

否则,不妨让每 \(max(x, y)\) 轮一组,每组的第二个选手赢。因为从第二组开始,第一个人必须输。

枚举 \(\frac{n - 1}{max(x, y)}\) 轮,每轮 \(max(x, y)\) 次,时间复杂度 \(O(n)\)

view
#include <bits/stdc++.h>
long long gcd(long long a, long long b) {return b?gcd(b,a%b):a;}
void solve() {
	int n, x, y; std::cin >> n >> x >> y;
	if (std::min(x, y) != 0 || gcd(n-1, std::max(x, y)) != std::max(x, y)) {
		std::cout << -1 << '\n';
	}
	else {
		for (int i = 1; i * std::max(x, y) < n; i++)
			for (int j = 1; j <= std::max(x, y); j++)
				std::cout << (i - 1) * std::max(x, y) + 2 << " \n"[i == n - 1 && j == std::max(x, y)];
	}
}
signed main() {
	int _ = 1; std::cin >> _;
	while (_--) solve();
	return 0;
}