We hope you enjoyed the problems! Thank you for participating in the contest! We would love to hear your feedback in the comments.
When Fofo is the spectator of the first match, what is the earliest subsequent game in which he will spectate again?
Suppose Sosai wins the first game. What becomes clear?
Once the winner of the first match is decided, the rest of the game is completely predictable.
For example, if Hohai wins the first match which Fofo spectated, we can see that:
No matter who wins in the second match, Hohai won't be able to continue playing in the third match (even if he wins the second match) since he has already played two times in a row. Similarly, Fofo won't be able to play in the fourth match because he has already played twice in a row, regardless of the match result.
As a result, Fofo won't be able to spectate in the $$$k$$$-th match for any $$$k$$$ of the form $$$3x + 1$$$.
The overall time complexity is: $$$O(1)$$$.
#include<bits/stdc++.h>
using namespace std;
void solve() {
int k;
cin >> k;
if (k % 3 == 1) {
cout << "Yes\n";
} else {
cout << "No\n";
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
Consider the identity permutation, defined by $$$p_i = i$$$. When and why does this permutation not work?
The smallest index $$$i$$$ where the issue occurs must satisfy the condition that $$$1 + \ldots + i$$$ is a perfect square. What is the simplest and most efficient way to resolve this issue?
The first observation is that if the sum $$$1 + 2 + … + n = \frac{n(n+1)}{2}$$$ is a perfect square, no valid perfect permutation exists.
To prove that a solution always exists otherwise, start with the identity permutation $$$p_i = i$$$ and iterate through indices from $$$1$$$ to $$$n$$$. We keep on iterating as long as the prefix sum till that moment isn’t a perfect square. If the prefix sum up to index $$$k$$$ becomes a perfect square, $$$\frac{k(k+1)}{2} = x^2$$$, swap $$$p_k$$$ and $$$p_{k + 1}$$$. This changes the prefix sum to $$$x^2 + 1$$$, which is not a perfect square.
To ensure this method works, we must show that $$$\frac{(k+1)(k+2)}{2}$$$ cannot also be a perfect square. Assume for contradiction that $$$\frac{(k+1)(k+2)}{2} = y^2$$$. Then:
Since $$$x > \frac{k}{2}$$$ (because $$$x^2 = \frac{k(k+1)}{2} > \frac{k^2}{4}$$$), we have:
which is a contradiction. Thus, $$$\frac{(k+1)(k+2)}{2}$$$ cannot be a perfect square, and the process can be repeated until all indices are processed, ensuring a valid permutation.
The overall time complexity is: $$$O(n)$$$.
#include<bits/stdc++.h>
using namespace std;
void solve() {
auto check = [&](int k) {
int j = sqrtl((int64_t)k * (k + 1) / 2);
return ((int64_t)j * j != (int64_t)k * (k + 1) / 2);
};
int n;
cin >> n;
if (!check(n)) {
cout << "-1\n";
return;
}
vector<int> ans(n + 1);
for (int i = 1; i <= n; i++) {
ans[i] = i;
}
int j = 0;
for (int i = 1; i <= n; i++) {
while ((int64_t)j * j < (int64_t)i * (i + 1) / 2) j++;
if ((int64_t)j * j == (int64_t)i * (i + 1) / 2) {
swap(ans[i], ans[i + 1]);
}
cout << ans[i] << " ";
}
cout << "\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
Root the tree at vertex $$$\textrm{en}$$$. What observations can you make?
Can the cheese be placed at the vertices in a specific sequence that prevents the mouse from moving farther away from vertex $$$\textrm{en}$$$?
First, root the tree at vertex $$$\textrm{en}$$$ and approach it step by step. Observe that after processing all vertices at the largest depth $$$n−1$$$, the mouse’s current depth cannot exceed $$$n−1$$$. By repeating this process for the next largest depth $$$n−2$$$, the mouse’s depth will inevitably become $$$n−2$$$ or less. Continuing this way, we process vertices in descending order of depth until we reach the root, achieving the desired result.
The overall time complexity is: $$$O(n)$$$.
#include<bits/stdc++.h>
using namespace std;
void solve() {
int n, s, e;
cin >> n >> s >> e;
vector adj(n + 1, vector<int> ());
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v), adj[v].push_back(u);
}
vector dis(n + 1, vector<int> ());
vector<int> d(n + 1);
auto dfs = [&](auto &&self, int v, int par) -> void {
d[v] = d[par] + 1;
dis[d[v]].push_back(v);
for (int u: adj[v]) {
if (u == par) continue;
self(self, u, v);
}
};
dfs(dfs, e, 0);
for (int i = n; i >= 1; i--) {
for (int j: dis[i]) {
cout << j << " ";
}
}
cout << "\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
2071D1 - Infinite Sequence (Easy Version)
Try to determine the connection between $$$a_{2m}$$$ and $$$a_{2m+1}$$$ for indices where $$$2m > n$$$.
Try to express $$$a_{2m}$$$ as the XOR of a short prefix of terms plus at most one extra term.
For convenience, assume $$$n$$$ is odd (if not, increment $$$n$$$ and handle the edge case separately). Start by precomputing the first $$$2n$$$ terms $$$a_1, a_2, \ldots, a_{2n}$$$. For queries with indices less than or equal to $$$2n$$$, directly return the precomputed value. For $$$2m>n$$$, observe the following relationship
Define $$$p = a_1 \oplus a_2 \oplus \ldots \oplus a_n$$$. Notice that when $$$m > n$$$, we can decompose the XOR sum as:
Since $$$n$$$ is odd, the pairs $$$(a_{n + 1} \oplus a_{n + 2}), (a_{n + 3} \oplus a_{n + 4}), \ldots$$$ cancel out. This simplifies the formula to:
As a result, we can compute $$$a_m$$$ recursively by halving $$$m$$$ until $$$m \le 2n$$$, applying the parity rule at each step.
The overall time complexity is: $$$O(n+\log(m))$$$.
#include<bits/stdc++.h>
using namespace std;
void solve() {
int n;
int64_t l, r;
cin >> n >> l >> r;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> pref(n + 1);
for (int i = 1; i <= n; i++) {
pref[i] = pref[i - 1] + a[i];
}
if (n % 2 == 0) {
n++;
int cur = pref[n / 2] & 1;
a.push_back(cur);
pref.push_back(pref.back() + cur);
}
for (int i = n + 1; i <= n * 2; i++) {
a.push_back(pref[i / 2] & 1);
pref.push_back(pref[i - 1] + a[i]);
}
int p = pref[n] & 1;
auto get = [&](int64_t x) {
int ret = 0;
while (true) {
if (x <= n * 2) {
ret ^= a[x];
break;
}
ret ^= p;
if ((x / 2 - n) % 2 == 0) {
break;
}
x /= 2;
}
return ret;
};
cout << get(l) << "\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
2071D2 - Infinite Sequence (Hard Version)
Generalize the recursive method for evaluating an index to handle the computation of the prefix sum.
First, check the editorial of D1.
To upgrade the solution, we define a recursive function:
We precompute the even and odd prefix sums for $$$m \le 2n$$$. For $$$m > 2n$$$, the term $$$a_m$$$ follows:
For simplicity, assume $$$m \equiv 1 \pmod{4}$$$ (if not, keep incrementing $$$m$$$ and adjusting its contribution separately).
Define
This sum can be expressed as:
The pairs we're interested in computing are (keep in mind that $$$n$$$ is odd):
Notice that the sums of the above even and odd indices are equal, and depend on $$$p$$$:
Thus, the final sums are:
As a result, we can compute $$$\text{sum}(m)$$$ recursively by halving $$$m$$$ until $$$m \le 2n$$$, benefitting the precomputed even and odd prefix sums at each step.
The overall time complexity is: $$$O(n+\log(m))$$$.
#include<bits/stdc++.h>
using namespace std;
void solve() {
int n;
int64_t l, r;
cin >> n >> l >> r;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> pref(n + 1);
for (int i = 1; i <= n; i++) {
pref[i] = pref[i - 1] + a[i];
}
if (n % 2 == 0) {
n++;
int cur = pref[n / 2] & 1;
a.push_back(cur);
pref.push_back(pref.back() + cur);
}
for (int i = n + 1; i <= n * 2; i++) {
a.push_back(pref[i / 2] & 1);
pref.push_back(pref[i - 1] + a[i]);
}
vector<int> even(n * 2 + 1);
for (int i = 1; i <= n * 2; i++) {
even[i] = even[i - 1] + (i & 1 ? 0 : a[i]);
}
int p = pref[n] & 1;
auto get = [&](int64_t x) {
int ret = 0;
while (true) {
if (x <= n * 2) {
ret ^= a[x];
break;
}
ret ^= p;
if ((x / 2 - n) % 2 == 0) {
break;
}
x /= 2;
}
return ret;
};
auto sum = [&](auto&& self, int64_t m) -> pair<int64_t, int64_t> {// {sum even, sum odd}
if (m <= n * 2) {
return {even[m], pref[m] - even[m]};
}
int64_t eve = even[n * 2 - 1], odd = pref[n * 2 - 1] - eve;
if (m % 2 == 0) {
m += 1, odd -= get(m);
}
if (m / 2 % 2) {
m += 1, eve -= get(m);
m += 1, odd -= get(m);
}
auto [e, _] = self(self, m / 2);
e -= even[n];
int64_t c = m / 2 - n + 1, both = (p ? c - e : e);
eve += both, odd += both;
return {eve, odd};
};
int64_t ans = 0;
auto [re, ro] = sum(sum, r);
ans += re + ro;
auto [le, lo] = sum(sum, l - 1);
ans -= le + lo;
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
Think about an unordered pair $$$(u, v)$$$ where both u and v are leaves in the final forest. Consider dividing all such pairs into separate categories based on their relationship in the original tree.
Let the first category be the pairs that are directly connected (neighbors), and analyze under what conditions both vertices become leaves.
For the pairs that are not direct neighbors, focus on those that share a common neighbor. Investigate how the state (fallen or not) of their neighbors influences the possibility of both vertices becoming leaves.
Let $$$fall_{i} $$$ denote the probability that the $$$i$$$-th node falls. We partition the unordered pairs $$$(u,v)$$$ into three categories:
- $$$u$$$ and $$$v$$$ are direct neighbors.
- $$$u$$$ and $$$v$$$ share a common neighbor.
- Pairs that do not satisfy the first two conditions.
Now, let us analyze the contribution of the first category to the final answer. For a pair $$$(u,v)$$$ of direct neighbors, both vertices become leaves if neither $$$u$$$ nor $$$v$$$ falls and if all of their other neighbors fall. Thus, the contribution of a specific pair $$$(u,v)$$$ is given by:
The whole contribution of the first category is:
For the second category, $$$u$$$ and $$$v$$$ share a neighbor, so this shared neighbor either must be the only one not falling among the neighbors of $$$u$$$ and $$$v$$$, or it must fall and exactly one of the other neighbors of both $$$u$$$ and $$$v$$$ must not fall. Additionally, both $$$u$$$ and $$$v$$$ must not fall anyway. Therefore, the contribution for a pair $$$(u,v)$$$ in the second category is given by:
where $$$s$$$ is the shared neighbor of $$$u$$$ and $$$v$$$.
The whole contribution of the second category is:
Moving to the third category: Here, $$$u$$$ and $$$v$$$ are neither direct neighbors nor do they share any common neighbor. In this case, the events that $$$u$$$ and $$$v$$$ become leaves are completely independent.
Define $$$leaf_{i} = (1 - fall_{i}) \cdot (\prod_{c \text{ is a neighbor of } i} fall_{c}) \cdot (\sum_{c \text{ is a neighbor of } i} \frac{1 - fall_{c}}{fall_{c}})$$$ as the probability that vertex $$$i$$$ becomes a leaf. Hence, for a pair $$$(u,v)$$$ in this category, the contribution is given by:
The whole contribution of the third category is:
The final answer is obtained by summing the contributions from all three categories. We can compute the contribution of the third category by summing $$$leaf_{i} \cdot leaf_{j}$$$ for all pairs $$$(i, j)$$$ with $$$i < j$$$, and then subtracting the contributions corresponding to pairs that satisfy one of the first two categories. The contribution of the second category can be computed by iterating over each node and accumulating the contributions from its neighbors (since these pairs share that node as their only common neighbor). The contribution of the first category can be computed in linear time too.
The overall time complexity is $$$O(n \cdot \log M)$$$, where the $$$\log$$$ factor arises from the modular inverse computations.
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int add(int x, int y) {
return x + y - (x + y >= mod) * mod;
}
void add2(int &x, int y) {
x += y;
if (x >= mod) x -= mod;
}
int mul(int x, int y) {
return int((int64_t)x * y % mod);
}
int sub(int x, int y) {
return x - y + (x < y) * mod;
}
void sub2(int &x, int y) {
x -= y;
if (x < 0) x += mod;
}
int pwr(int x, int y) {
int ret = 1;
while (y) {
if (y & 1) ret = mul(ret, x);
x = mul(x, x);
y /= 2;
}
return ret;
}
int inv(int x) {
return pwr(x, mod - 2);
}
int norm(int64_t x) {
x %= mod;
if (x < 0) x += mod;
return int(x);
}
void solve() {
int n;
cin >> n;
vector adj(n + 1, vector<int> ());
vector<int> p(n + 1);
for (int i = 1; i <= n; i++) {
int q;
cin >> p[i] >> q;
p[i] = mul(p[i], inv(q));
//here, p[i] is the probability that node i will fall
}
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v), adj[v].push_back(u);
}
vector<int> p1(n + 1), p2(n + 1);
for (int i = 1; i <= n; i++) {
p1[i] = sub(1, p[i]);
for (int u: adj[i]) {
p1[i] = mul(p1[i], p[u]);
}
//p1[i] is the probability that node i won't fall, but all nodes around it will fall
for (int u: adj[i]) {
add2(p2[i], mul(p1[i], mul(inv(p[u]), sub(1, p[u]))));
}
//p2[i] is the probability that node i will be a leaf (it won't fall, all it's neighbors except one will fall)
}
int ans = 0, sum = 0;
for (int i = 1; i <= n; i++) {
add2(ans, mul(p2[i], sum));
add2(sum, p2[i]);
}
//take all contributions of unordered pairs
for (int i = 1; i <= n; i++) {
//recalculate the contribution of neighboring pairs
for (auto u: adj[i]) {
if (u < i) continue;
//avoid calculating the same pair probabilty twice
int pi = mul(p1[i], inv(p[u]));
//pi is the probability that every neighbour of i would fall except for u (not including the probability of u not falling down)
int pu = mul(p1[u], inv(p[i]));
//pu is the probability that every neighbour of u would fall except for i (not including the probability of i not falling down)
//this case is just a tree of 2 nodes, both of them are leaves
add2(ans, mul(pi, pu));
//subtract the old contribution
sub2(ans, mul(p2[i], p2[u]));
}
//recalculate the contribution of pairs with a shared neighbour which is node i (ie calculate the contribution for pairs u, v such that dis(u, v) = 2 and dis(u, i) = dis(v, i) = 1
sum = 0;
for (int u: adj[i]) {
sub2(ans, mul(sum, p2[u]));
add2(sum, p2[u]);
//subtract the old contribution
}
//p[i] doesn't fall
sum = 0;
for (int u: adj[i]) {
int pu = mul(p1[u], inv(p[i]));
//pu is the probability that node u is a leaf connected to node i
add2(ans, mul(sum, pu));
add2(sum, mul(pu, sub(1, p[i])));
}
//p[i] falls
sum = 0;
for (int u: adj[i]) {
int pu = sub(p2[u], mul(p1[u], mul(inv(p[i]), sub(1, p[i]))));
//pu is the probability that node u is a leaf not connected to node i
add2(ans, mul(sum, pu));
add2(sum, mul(pu, inv(p[i])));
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--) {
solve();
}
}
Binary search on $$$p$$$. After fixing $$$p$$$, find the maximum $$$p$$$-towering subsequence.
if we denote the set of indexes that correspond to the maximum "increasing" $$$p$$$-towering subsequence on prefix $$$i$$$ as $$$S_i$$$, then for any $$$i < n$$$: $$$S_i \subseteq S_{i + 1}$$$.
Let's do binary search on $$$p$$$. After fixing some $$$p$$$ our goal is to find the maximum $$$p$$$-towering subsequence and check if the length of that subsequence $$$s$$$ satisfies $$$n - s \le k$$$.
To find the maximum $$$p$$$-towering subsequence, for each index $$$i$$$ we will find the maximum $$$p$$$-towering subsequence such that the "left" part of that subsequence is in prefix $$$i$$$ and its right part is in suffix $$$i$$$.
Let's focus only on prefixes, as the suffixes can be done similarly. So, for each prefix $$$i$$$ we want to find the maximum "increasing" $$$p$$$-towering subsequence. To do it, we will traverse the array from left to right and maintain the currently found maximum subsequence. The key idea here is that as you move from left to right you only need to add new elements to the "increasing" subsequence and never delete any (or, formally speaking, if we denote the set of indexes that correspond to maximum "increasing" $$$p$$$-towering subsequence on prefix $$$i$$$ as $$$S_i$$$, then for any $$$i < n$$$: $$$S_i \subseteq S_{i + 1}$$$ (the proof is left to the reader).
Before moving to the details of implementation, let's elaborate a bit on the previous paragraph. Consider the fifth test case from the sample; suppose the current $$$p = 7$$$; and we have just arrived at the tenth element (denoted with star $$$^*$$$). Before this position, the maximum "increasing" $$$p$$$-towering subsequence consists of the first, third, and fifth elements (denoted with underlines):
$$$[\underline{6}, 3, \underline{8}, 5, \underline{8}, 3, 2, 1, 2, 7^*, 1]$$$.
Now we need to check if we can increase the size of the subsequence. Since $$$p = 7$$$, then we certainly can add the tenth element with value $$$7$$$ to the subsequence. However, since we add a new number to the subsequence, two numbers become available: the second one with value $$$3$$$ and the forth one with value $$$5$$$. Thus, after processing the tenth element, the maximum "increasing" $$$p$$$-towering subsequence will look like this:
$$$[\underline{6}, \color{red}{\underline{3}}, \underline{8}, \color{red}{\underline{5}}, \underline{8}, 3, 2, 1, 2, \color{red}{\underline{7}}^*, 1]$$$.
So we need some way to find such "new" numbers that appear when we add some elements to the subsequence (like when the element with value $$$5$$$ becomes available from the example). To resolve this we first assign $$$a_i := p - a_i$$$ for each $$$i$$$. To find the positions that are becoming available, we can search for the rightmost non-positive element on the current prefix. Once found (suppose its index is $$$j$$$), decrease all elements on the prefix $$$j$$$ by one and assign $$$a_j := \infty$$$ (to avoid this position in the future). All these operations can be performed with the help of a segment tree.
This concludes the asymptotic complexity: $$$O(n \log{C} \log{n})$$$.
#include <bits/stdc++.h>
#define len(a) (int)a.size()
#define all(a) a.begin(), a.end()
using namespace std;
const int MAXI = 1e9 + 1e7;
const int MAXN = 2e5 + 100;
struct Node {
int min_on_subtree = 0, push_addition = 0;
};
Node t[MAXN * 4];
int a[MAXN], pref[MAXN], suf[MAXN];
class Segtree {
private:
int n;
void add_on_subtree(int u, int val) {
t[u].push_addition += val;
t[u].min_on_subtree += val;
}
void push(int u) {
if (t[u].push_addition) {
add_on_subtree(u * 2 + 1, t[u].push_addition);
add_on_subtree(u * 2 + 2, t[u].push_addition);
t[u].push_addition = 0;
}
}
void recalc(int u) {
t[u].min_on_subtree = min(t[u * 2 + 1].min_on_subtree, t[u * 2 + 2].min_on_subtree);
}
void update(int u, int l, int r, int pos, int val) {
if (l == r) {
t[u].min_on_subtree = val;
} else {
push(u);
int mid = (l + r) / 2;
if (pos <= mid)
update(u * 2 + 1, l, mid, pos, val);
else
update(u * 2 + 2, mid + 1, r, pos, val);
recalc(u);
}
}
void add_on_segment(int u, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr)
add_on_subtree(u, val);
else {
push(u);
int mid = (l + r) / 2;
if (ql <= mid)
add_on_segment(u * 2 + 1, l, mid, ql, qr, val);
if (qr > mid)
add_on_segment(u * 2 + 2, mid + 1, r, ql, qr, val);
recalc(u);
}
}
int find_prev_non_pos_put_inf(int u, int l, int r, int pos) {
if (t[u].min_on_subtree > 0)
return -1;
if (l == r) {
t[u].min_on_subtree = MAXI;
return l;
}
push(u);
int mid = (l + r) / 2, res = -1;
if (pos > mid)
res = find_prev_non_pos_put_inf(u * 2 + 2, mid + 1, r, pos);
if (res == -1)
res = find_prev_non_pos_put_inf(u * 2 + 1, l, mid, pos);
recalc(u);
return res;
}
public:
explicit Segtree(int n): n(n) {
fill(t, t + 4 * n, Node{MAXI, 0});
};
void update(int pos, int val) {
update(0, 0, n - 1, pos, val);
}
void add_on_segment(int ql, int qr, int val) {
add_on_segment(0, 0, n - 1, ql, qr, val);
}
int find_prev_non_pos_put_inf(int pos) {
return find_prev_non_pos_put_inf(0, 0, n - 1, pos);
}
};
void f(int n, int p, int *res) {
Segtree tree(n);
int cur_sz = 0;
for (int i = 0; i < n; i++) {
tree.update(i, p - a[i]);
int pos = i;
while ((pos = tree.find_prev_non_pos_put_inf(pos)) != -1) {
cur_sz++;
tree.add_on_segment(0, pos, -1);
}
res[i] = cur_sz;
}
}
int32_t main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int testcases;
cin >> testcases;
while (testcases--) {
int n, k;
cin >> n >> k;
int max_a = -1;
for (int i = 0; i < n; i++) {
cin >> a[i];
max_a = max(max_a, a[i]);
}
int l = 0, r = max_a + 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
f(n, mid, pref);
reverse(a, a + n);
f(n, mid, suf);
reverse(a, a + n);
reverse(suf, suf + n);
int mx = -1;
for (int i = 0; i < n; i++) {
if (a[i] >= mid)
mx = max(mx, pref[i] + suf[i] - 1);
}
if (n - mx <= k)
l = mid;
else
r = mid;
}
cout << l << '\n';
}
}
very interesting problems!, thanks you all
B was Cool!
Very true! When i finally solved, I felt very happy NGL!!
The difficulty level of the first four questions and the last three questions is a bit high, TT,Does anyone think like me that the color of Specialist is the best among all levels.
Why is there no Hints on D???
We will add them soon
Ok thanks <3
Thanks.
How to come up with solutions for problems like C ? I figured en to be the last one in the permutation but couldn't progress further.
practice makes perfect
Obv, can you tell how you came up with solution for C ?
How do you write dfs? so in dfs you print root at before going to its childrens or after both are valid, since you thought en is last your brain needed to think how can i make en as last and make permuation which is ending at en so if you do a dfs from en that is your answer. so you are doing dfs and printing root at last and you wanted en to be last so en would be our root and since it is a tree path from st to en is always their.
He used post-order traversal
I actually got the same solution as the editorial
Basically, by past problem solving experiences, I tried rooting "en" because it was my target, so measuring how distant I am from it would be easier if it was the root because the distance will simply be the height of the current node
Then it was trial and error, initially I though about climbing the tree and then take turns on each neighbor of the root, until after some time testing I realized that if I did this backwards (starting from the deepest level) would make it easy to predict my height
Tbh the advice will always end up on "solve more problems" Like, rooting a node is a standard idea that you will see in many other tree problems, so at some point you expect this will help
Reverse dfs
You can do a simple post-order traversal on the tree and that would give you the answer.
What is the solution for D1?? is it standard typre problem??
I am shocked to find out that the answer for C doesn't depend on
st
Not all approaches, one may come up with some approach that really depends on
st
.Check my solution for example : 308367585
ye mine relies on
st
too. But the tutorial solution is really nice to know.https://codeforces.net/contest/2071/submission/308387650 why is my approach getting wa at tc 2 can anyone tell me what am i missing?
Consider the tree 2<->1<->3<->4<->5 with st 3 and en 5. Your code would print it 1, 2, 3, 4, 5, since 1 and 2 are in rem and 3 4 5 are in ans1. The way the rat would move like 3 -> 2 -> 1 -> 2 -> 3 -> 4, failing to reach 5.
The problem is that you are not printing the other nodes in order of their depth, but rather just the order of their number.
Ohhh yea got it,the path you told about my rat i didn’t follow that can you elaborate ?
Path should be 3->1->2->1->3->->4 and not reaching 5 so yea my ans ain’t right
what an amazing solution to C!
i had a completely different solution.
please share your approach
Key Observation: If we start at a vertex x and perform a postorder traversal rooted at x, we get all the vertices in x’s subtree and we end up at x. This can be verified with examples.
Solution Approach:
we root at st, If we are at en, we perform a postorder traversal and add all visited vertices to our answer. Otherwise, we perform a postorder traversal from each node between st and en, but we exclude the subtree containing en. We keep adding the visited nodes to our answer. Finally, we move into the subtree that contains en and continue the process. By following this approach recursively, we obtain the required answer.
can u tell like how did you get such a observation that for any subtree doing postorder will eventually lead to the current node itself . I had a stupid idea of first going to the target node and then keep choosing the leafnodes rooted at st . Idk what i was thinking . I thought of it as the push/pull kind of system .
i had the idea because i observed if we keep take lower nodes first, then go up from there, we would ultimately reach up as specified in the official solution, but then i realized, doing postorder which also lead to same conclusion.
you can visualize it with examples , its just that a reversed order
of traversal will allow you to reach half the distance then comeback
so if we take an example [1 , 2 , 3 , 4]
therefore the solution is just process all the nodes that doesnt lead to the end node in a reversed order (so that you come back where you started ready to visit other paths) , and process the nodes that lead to the end node in a normal order
you can also look at my code if you want https://codeforces.net/contest/2071/submission/308726433
hope that helps !!
My code is giving MLE , but the approach is same as that of yours
can you suggest how to optimise it ? please suggest how to get rid of memory limit exceeded error submission
i cant read cpp code unfortuantely , i am a python user
oh, btw thanks.
Will be added soon(
Love the problems thx guys (。♡‿♡。)
C was excellent. Really excellent.
what happened to D editorial
You can check it now. We added it.
What's the significance of
In D1 solution
I think it is just the main idea of the solution. This line checks whether x/2 is an odd number. If it is, this means that a_x will be just equal to p (p = a1^a2^a3^...^an) and we can stop executimg the loop -> stoping the recursion -> we got the answer
There is a very good explanation of that in a solution part
But why to subtract from n first?
I do not know, but in any case n is odd, so (x / 2 — n) % 2 == 0 will be just equevalent to (x/2) % 2 == 1
Let x be current x, and x/2 is next x. We already made n as an odd number. if ((x / 2 — n) % 2 == 0) is true, that means the number of elements from n+1 to x/2 (next x) is even. Again, that means xor sum of a[n+1]^a[N+2]^.....^a[x/2] is 0 as every 2 elements are the same. So yeah, if above if statements gives us true, we dont need to go further.
Great round ! The problems were well-balanced and had interesting ideas. Really enjoyed solving them, especially 2071B - Perfecto.
Thanks to the Setters and Testers for the effort :)
During the contest, I read task C incorrectly, which made it seem very difficult to me and I decided to skip it. I thought the mouse could NOT pass through en earlier during the process. Now I'm wondering, if there's any elegant and easy solution for this task, because the solution I was able to come up with doesn't seem simple.
Just Use Post Order Traversal from the end point and print the order. IG it works because when you try to the solve from the end point you have limited nodes to work with like 1 distance from end node and then 2... and so on.
No, I was talking about a modified version of the task(where mouse cannot pass through en earlier). This solution does not work in this case.
one solution to problem C is, rooting at en and placing the cheese at one of the remaining leaf nodes (if en becomes leaf we avoid it) and keep doing until en remains. finally place at en.
let R be set of remaining nodes on which cheese hasnt been placed. it happens that rat will always be present in R or neighbours of nodes in R. i cant prove it, but proof by AC.
you can similary use this theory for the modified version. let SZ be sum of all subtress of children of en. and SZV be size of the child subtree in which en is present. if SZ — SZV >= SZV, you will always pass en and have some remaining nodes. for SZ — SZV < SZV, we can call alternatingly and make SZ — SZV = 0, then the remaining tree will be tree rooted at en, and subtree in which en is present only. for this tree you can use my approach to reach en at the end.
point out if anything was "unclear"
I think this round is harder than the Edu round 1006, but at least the problem is interesting. My friend encountered serveral corner cases which made him crazy!
Thank you for the great problems! I really enjoyed problem C, it was very nice. For problem B, I used a randomized solution 308317488.
Why should we double n when we solve problem D?
Same question
Now I get it.It can ensure that every unknown number includes a1^a2^...an.Then we can get "both" more easily.
I got it. Thanks!
Where can I see the testcases for problem B?
I had tried a different solution than the editorial, for Problem C. You can root the tree at node st, and then start a DFS traversal from the root, while pushing back values in an answer list. Say current node is u, then 3 cases arise:
subtree of node u doesn't contain the en node: then first visit all children, and then pushback u (post-order)
u is the en node: then again, do post-order
subtree of u contains en node, but u is not en node: then first visit all branches of the tree that don't have the en node, and then pushback u, and then visit the branch containing en node (in-order).
https://codeforces.net/contest/2071/submission/308386874
The basic idea is that, if you are standing at root of a tree, and you place the cheese in the order of post-order traversal for the nodes of tree other than the root, then in the end, you will end up at an immediate chid of the root, and then placing cheese at the root, will bring you back to root.
Sir's, round was so cool and problems are good quality, if you add 2 more hard problems round will be definitely a good Div1+2 :)
For problem C I have taken the root as en and then the post order traversal of that tree gives the permutation. Not sure why this is working. Can someone help in building the intuition behind this approach?
https://codeforces.net/contest/2071/submission/308378910
+1
For c , My approach was that we are starting with node start , then we will have one and only path from start to end , lets use this path at the very last in permutation , it means that after performing all non final path edge (ie nodes that are not in this path) we have to land on starting node , but how to do this ??
This might probably be the simplest solution to problem B (although very tough to come up with):
I verified the solution by confirming that for all n from 5 to 5e5, (n * (n + 1) / 2) — 4 is not a perfect square. You can have a look at my submission here
Also in problem B if $$$\frac{n*(n + 1)}{2}$$$ is not a perfect square you can just generate random permutations submission
Why won't this TLE?
Not a formal way to put it, but there aren’t that many squares.
2071D1 - Infinite Sequence (Easy Version) can anyone tell me in D1 why n is needed to converted to odd . please explain the solution to me.
Because each even number cancels out its subsequent odd number. When n is odd, (n+1) will be even and (n+2) is odd. Therefore, they will cancel out each other.
It's just a trick to make the computations easier. You can solve the problem without it (but you will need to handle (n+1)-th term each time separately).
Now I understand! Thanks for the explanation.
Why in D1 we extend a till (2 * n). Why can't we stop after making n odd and have the following condition instead of (x <= 2 * n)? if (x <= n) { ret ^= a[x]; break; }
Is it just me or B seems easier than average Div 2 contests cuz I usually take 1 hour to do this problem but for some reason, I did this B in 20 min
My solution for D2.
First, check the editorial of D1.
To upgrade the solution, we define the function: $$$\text{sum}(m) = \displaystyle\sum_{i = 1} ^ {m} a_i.$$$ This function can be implemented recursively like this:
It’s clear that when computing $$$a_{2i}$$$ and $$$a_{2i+1}$$$, we only care about whether $$$i$$$ is even or odd and the value of $$$a_i$$$, which effectively reduces the number of states.
However, there’s still an issue: the condition $$$i \leq m$$$. We need to know $$$i$$$, right?
No, but we need to keep track of some additional information, let $$$br(i)$$$ be the binary repression of $$$i$$$. When transitioning $$$i$$$, we either append a $$$0$$$ or $$$1$$$ to the end of $$$br(i)$$$.
If $$$br(i)$$$ is not a prefix of $$$br(m)$$$, the number of transitions becomes fixed, its either $$$|br(m)| - |br(i)|$$$ or $$$|br(m)| - |br(i)| - 1$$$, depending on which is lexicographically greater.
Thus, we only need to track $$$i$$$ if $$$i \leq n$$$ or $$$br(i)$$$ is a prefix of $$$br(m)$$$. Otherwise, we only keep track of $$$i \text{ mod } 2$$$ and the remaining number of transitions.
The overall complexity is $$$O(n * log(m))$$$
Thank you very much for the hints you left for each question. I wish all contests had this...
Alternative solution for B
Squares, divided by $$$4$$$, leaves a remainder of either $$$0$$$ or $$$1$$$.
$$$2 + 4 + 6 + …$$$ is not square
$$$2+4+…+2k = k(k+1)$$$, which cannot be a square.
Basically $$$2 + 4 + … + 1 + 3 + …$$$ works. However, if the last even numbers divided by $$$8$$$ gives the remainder of $$$6$$$ or $$$0$$$ then remove it and put it at the back.
The first prefix consisting of even numbers is not square by Hint 2. The next prefixes leave a remainder of $$$2$$$ or $$$3$$$ divided by $$$4$$$, so it cannot be square.
For problem E, a vertex becomes a leaf if it is connected to exactly one edge. But in the editorial, for the third category all the neighbors are being removed. How would the vertex become a leaf with zero edges connected to it?
Thanks for catching this mistake, exactly one of the neighbours must not fall. Fixed.
In the solution of problem E in order to calculate contribution2(u, v) you separate it to two cases: when u and v share a neighbor s,
In the editorial, the value for the second case (2.) is
However, $$$(1 - fall_{s})$$$ implies that s is not removed from the tree. Should this not be $$$fall_{s}$$$ instead? Thus, I think (2.) should be given by
Fixed, thanks!
I think there is a mistake in E's editorial (I might be wrong).
In the second category, u and v can share a common neighbour, but we need to calculate the probability that they become leaves whilst also having the common neighbour falls (it can happen that a neighbour of u doesn't fall (other than s) and a neighbour of v doesn't fall (other than s) and s falls and all other neighbours of u and v fall.
You're absolutely right, fixed.
this code giving TLE is it any but its time complexity is O(n)
(x+1)^2≤y^2 in problem B shouldn't it be ? (x+1)^2 > y^2
Therefore, $$$(x+1)^2 \leq y^2$$$.
However, the sum of integers up to $$$k+1$$$ cannot be a perfect square because this will lead to a contradiction $$$(x+1)^2 > y^2$$$
Problem C can be solve by rooted en and doing postorder transversal Claim:I am new and not professional,so please correct me for wrong proof
If you are looking for not professional proof then you can skip this part. First,we need to do some heuristic observation,if we can't solve problem with n=1e5,then we can try solve with n is small for example n=3,assume a tree with n=3 vertex with edge (1,2),(1,3),we assume that 1 is the root,then no matter which vertex(1 or 2 or 3) we choose,the end point will always be 1,then we can try for n=4,n=5,...,the answer is still satisfy the criterion above,so this may be a correct idea,then we can try to do a simple prove.
Claim 1:If the mouse currently at point u and postorder transversal is at subtree of point u then the mouse will definitely end at root of subtree. As the observation before we found that no matter start point at where the end point always is root but why?The main reason is the characteristic of postorder,in postorder parent will located at the end so there is two thing will happen,after transversal at the last point,first we are at parent,in this problem if we transverse for A to A then we will not move,so obviouly we will at the parent,Second if we are at the child,then we will transverse from child to parent,so we will also end at parent,after this we prove for n=3 then you can generalized to n=k by mathematical induction
Claim 2:No matter start point at where,the transversal will meet the mouse. By the claim 1,if the transversal is currently at the point with mouse then mouse will end at the root,so we want to prove that this thing will definitely happen.
There is two condition,you can separate the child of the root into two part,let say L part and R part, Since postorder start from left part(from left to right,from bottom to root),then First if the mouse is also at L part, obviously when mouse is at L part then when postorder start,the transversal will start from bottom to top,and the mouse will move from top to bottom then they will meet. Second,if the mouse is al R part,there also two condtion which is,before L part end the mouse move from R part to L part then by the previous result if the mouse and transversal is at the same part they will meet,or when L part end mouse still at R part but transveral will move from L part to R part which is same part with mouse,so they will also meet. So mouse and the transversal will always meet.
This is a roughly proof and not professional 308771732
A video tutorial for E . Let me know if you have any feedback!
Goated
I didn't understand the editorial for D2, could someone explain it?
I didn't understand the editorial either, especially the 1 mod 4 part but here's my solution:
There are two key high level ideas used here. 1. whenever asked about ranges try calculating prefix sums. (This is highly useful in digit dp problems) 2. 1^x = 1-x if x $$$\in$$$ {0,1}
now first observe nature of P (the prefix xors)
for i > 2*n+1 you have BASE^$$$A_{2*n+2}$$$ , BASE, BASE^$$$A_{2*n+4}$$$, BASE .. (Notice how only even indices of A are used here!)
where BASE = $$$P_n$$$ ^ $$$A_{n+1}$$$ (if n is even) and $$$P_n$$$ (if n is odd).
now observe the nature of A
for i > n you have $$$A_i$$$ = $$$P_{i/2}$$$ so for some 2*k > n $$$A_{2*k}$$$ = $$$A_{2*k+1}$$$ = $$$P_{k}$$$
so if you're asked for the prefix sums of A -> you're actually asking the prefix sums of P for half the length. (This should brighten a bulb inside you which screams log(n) )
now if you're asking to calculate the prefix sums of P upto k you realize its some recomputable term upto 2*n+1, and after that you alternate between BASE and BASE^(even term of A). you can count the number of BASE that would appear upto K and add it up and what's left are BASE^$$$A_{2*k}$$$ terms.
since you know after n : $$$A_{2*k}$$$ = $$$A_{2*k+1}$$$ = $$$P_{k}$$$ you can use this to write down the prefix sum of A as a function of the sums upto n, the sum of even terms and odd terms after n. and this gives you a way of computing the sum of even terms !
you now have all the recipes for your solution. when asked about prefix sum of A upto k => you ask what's the prefix sum of P upto k/2 which asks the sum of even terms upto k/2 and so on. The trick for computing sums where each term is xor'd with BASE when BASE = 1 is : term^1 = 1 — term.
I leave the implementation details for you to figure out but here's my submission : 308654304
Thank you for sparing time to explain your solution.
could someone explain the jiangly's solution to problem F?
If you need to eat as much cheese as possible for question C, is there a solution?
even tho , the solution will be the same , no ?
As you can only move one edge per cheese location thus you can only collect half the cheese
in a certain path , as you need to comeback for visiting other paths
correct me if i am wrong !
If the node where s is located has a large depth, should it be put into the subtree of s according to the depth first?
i dont exactly understand what you mean by S ,
i think cause of the traversing constraints of the problem , you can only
collect half the cheese at each path (where en node is the root) , it
doesnt really matter how deep that path is ,
For example if this is your path 1 -> 2 -> 3 -> 4
that should be the cheese distrubtion
Cheese at 4: The mouse moves one edge: from 1 to 2.
Cheese at 3: The mouse moves one edge: from 2 to 3.
NOW you are gonna start collecting the cheese on your way back
Cheese at 2: The mouse moves one edge: from 3 back to 2.
Cheese at 1: The mouse moves one edge: from 2 back to 1.
this cheese distribution permutation is pretty much needed as it is the only one that guarntees ending at en , any other permutation is risking going too deep into a path
I'm sorry, I'm not very good at English, I mean whether a different starting point will lead to a better result for a different arrangement of nodes of the same depth, or an arrangement that can go back to the end point if it doesn't exactly follow the order of depth priority
good question , No a different starting node doesnt matter
also we dont visit paths depending on there depths' , the
whole idea is just to reverse all the paths connected to the
end node , it doesnt matter which order you go in reversing
them , you just need them reversed
When the submissions will be rejudged??
or detecting cheaters for this round??
In the editorial for F, in Elaboration, shouldn't the maximum "increasing" p-towering subsequence will look like this after processing 10th index: [6,3,8,5,7] (3 will be included as well, right?)
How to calculate $$$e$$$ in D2?
The sum over even-indexed elements in the range $$$[n + 1, \lfloor \frac{m}{2} \rfloor]$$$ is defined as:
To compute this efficiently, we utilize the recursive function $$$\text{sum}(\lfloor \frac{m}{2} \rfloor)$$$ that returns two values: the sum of even-indexed and odd-indexed terms up to $$$\lfloor \frac{m}{2} \rfloor$$$. To exclude terms before $$$n + 1$$$, we subtract the prefix sum of even indices up to $$$n$$$:
I think D2 can be solved even if we allow array values to be up to 1e18, something like this https://codeforces.net/contest/2071/submission/308895384
since the sum of the interval to find can exceed long long limit maybe we could find mod of the value?
Yeah but I think it's straightforward and not very interesting.
for B, you can simply find the values (say k) that such 1 + 2 + 3 ... + k is a perfect square (there are only a few). You can avoid this subarray by swapping k with the number ahead of it, ie making the sequence 1 + 2 + 3 ... k-1 + k+1 + k. If theres no "next" number, the answer is -1.
Like this
exactly how i did
All you need is attention.For C,just dfs from en and output the index when backtracking.I found this after a long thought.
I think there is a typo in the solution of Problem A.
As a result, Fofo won't be able to spectate in the k-th match for any k of the form 3x+1.
It should be-
As a result, Fofo would be able to spectate in the k-th match for any k of the from 3x+1.
Why is java O(n) code for problem B giving TLE. submission
my code for second question i implemented differently 310238565 ~~~~~
int n;cin>>n;
int sum=(n*(n+1))/2;
if(floor(sqrt(sum))==ceil(sqrt(sum)))
{
cout<<-1<<"\n";
return;
}
else
{
{ if(i!=8)
}
cout<<8<<" ";
cout<<"\n";
return;
cout<<2<<" "<<1<<" ";
for (int i = 3; i <=n; ++i)
{
}
cout<<"\n"; } ~~~~~
why we must prove (k + 1)(k + 2) / 2 cannot also be a perfect square ? i don't understand
i received a warning for a submission but i haven't cheated i just formatted the code so may be the code looks same so it is humble request not to take any strict action against me. Hope you understand thank you.