Codeforces Round 1007 (Div. 2)
A. The Play Never Ends
题意:三个人比赛,每场两个人比赛,另一个人在观众席,观众席替换输的人,但如果有一个人以及连续上场两次,就得下场,让其它两个人比。求第一场比赛在观众席的人在第\(k\)场是不是也能在观众席。
找规律,模拟一下发现第二三场不得不上台,然后第四场下台,就这样一直循环。于是看取余3是不是1。
点击查看代码
void solve() {
int n;
std::cin >> n;
if (n % 3 == 1) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
B. Perfecto
题意:构造一个排列,使得没有一个前缀的和是平方数。
先按1到n的顺序排好,然后从前往后看,如果当前位置的前缀和是平方数,就和后面的数换,这样前缀和会加一,就不是平方数。要特判\(\sum_{i=1}^{n} i\)是平方数的情况。
点击查看代码
void solve() {
i64 n;
std::cin >> n;
i64 sum = n * (n + 1) / 2;
i64 t = std::sqrt(sum);
if (t * t == sum) {
std::cout << -1 << "\n";
return;
}
if (n == 2) {
std::cout << 2 << " " << 1 << "\n";
return;
}
std::vector<int> ans(n);
std::iota(ans.begin(), ans.end(), 1);
i64 pre = 0;
for (int i = 0; i < n; ++ i) {
pre += ans[i];
i64 t = std::sqrt(pre);
if (t * t == pre) {
pre -= ans[i];
std::swap(ans[i], ans[i + 1]);
pre += ans[i];
}
}
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
}
C. Trapmigiano Reggiano
题意:给你一棵树,有一个老鼠从\(st\)要到\(en\),你可以每次指出一个点,老鼠就会往这个点的方向移动一条边。给出一个操作的排列,使得最后老鼠在\(en\)。
这题也靠猜。
刚开始一直想以\(st\)为根这么拉扯可以到\(en\),后来发现以\(en\)为根,直接后序遍历输出就行。因为这样相当于从每个叶子开始往\(en\)操作,这样如果老鼠一定会往\(en\)靠近。
点击查看代码
void solve() {
int n, st, en;
std::cin >> n >> st >> en;
-- st, -- en;
std::vector<std::vector<int>> adj(n);
for (int i = 1; i < n; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
adj[u].push_back(v);
adj[v].push_back(u);
}
std::vector<int> ans;
auto dfs = [&](auto self, int u, int fa) -> void {
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
self(self, v, u);
}
ans.push_back(u);
};
dfs(dfs, en, -1);
for (auto & x : ans) {
std::cout << x + 1 << " \n"[x == ans.back()];
}
}
D1. Infinite Sequence (Easy Version)
题意:给出\(a\)的前\(n\)项,规定\(m > n, a_m = \oplus \sum_{i=1}^{\lfloor \frac{m}{2} \rfloor} a_i\),求\(a_m\)。
赛时已经想出\(n\)为奇数怎么做了,但因为已经写红温了,没想到\(n\)是偶数直接加一变成偶数就行了。
这里设\(n\)为偶数,如果不是我们就给他加一,然后预处理出\(1\)到\(2n\)的\(a\)以及前缀异或和\(sum\)。我们发现对于一个\(m\),\(\lfloor \frac{2m}{2} \rfloor = \lfloor \frac{2m + 1}{2} \rfloor\),这意味着\(a\)中大于\(n\)的项相邻两项是相同的,那么我们只需要看\(m\)奇偶性,如果是偶数则最后一项不能和前面消掉,就需要求\(a_{\frac{m}{2}}\),否则都消掉了,只剩下\(a\)的前\(n\)项异或和,这个我们已经求出来了。于是递归求解即可。
点击查看代码
void solve() {
i64 n, l, r;
std::cin >> n >> l >> r;
std::vector<int> a(3 * n + 1), sum(3 * n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
sum[i] = sum[i - 1] ^ a[i];
}
for (int i = n + 1; i <= 3 * n; ++ i) {
a[i] = sum[i / 2];
sum[i] = sum[i - 1] ^ a[i];
}
if (n % 2 == 0) {
++ n;
}
if (l <= 2 * n) {
std::cout << a[l] << "\n";
return;
}
auto get = [&](auto self, i64 m) -> i64 {
if (m <= 2 * n) {
return a[m];
}
if (m & 1) {
-- m;
}
m /= 2;
if (m & 1) {
return sum[n];
}
return sum[n] ^ self(self, m);
};
std::cout << get(get, l) << "\n";
}

浙公网安备 33010602011771号