Thank you for participating in Codeforces Round 1115 (Div. 2)! We hope you enjoyed the problems.
The round was prepared by Bufu and TomitaMatei, and coordinated by cry.
2252A - Boss Fight
The boss's shield permanently activates and blocks all subsequent damage only when two cards of the exact same value are played back-to-back. Importantly, the card that actually triggers the shield still deals its normal damage.
This means we want to play as many cards as possible before being forced to place two identical cards adjacent to each other. We should only do this on the very last card we play.
Let the most frequent card in our hand have a damage value of $$$X$$$, and let its frequency be $$$F$$$. Let the number of all other cards be $$$O = n - F$$$.
To maximize the number of $$$X$$$ cards we can play, we must use the $$$O$$$ "other" cards as separators. By placing an "other" card between every $$$X$$$ card, we can form an alternating sequence like this:
This allows us to safely play $$$O + 1$$$ copies of $$$X$$$ without triggering the shield.
Finally, to squeeze out the maximum possible damage, we can play exactly one more $$$X$$$ card at the very end of this sequence:
This final $$$X$$$ triggers the shield, but it still deals its normal damage. All remaining cards in our hand will deal $$$0$$$, but that doesn't matter because we have already used all of our "other" cards.
Thus, the maximum number of $$$X$$$ cards we can successfully play is $$$(O + 1) + 1 = O + 2$$$. Of course, if $$$F \lt O + 2$$$, we simply play all $$$F$$$ of our $$$X$$$ cards without any issues.
The maximum number of majority cards we can play is $$$\min(F, O + 2)$$$. Since we always play every single "other" card, the maximum total damage is:
Time complexity: $$$\mathcal{O}(n)$$$.
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
void solve() {
int n;
cin >> n;
long long total_sum = 0;
map<int, int> freq;
int max_f = 0;
int maj_val = 0;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
total_sum += x;
freq[x]++;
if (freq[x] > max_f) {
max_f = freq[x];
maj_val = x;
}
}
int others = n - max_f;
int max_majority_played = min(max_f, others + 2);
long long ans = (total_sum - 1LL * max_f * maj_val) + 1LL * max_majority_played * maj_val;
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}
2252B - Always Changing
Let $$$n_0$$$ and $$$n_1$$$ be the number of 0s and 1s in the initial string. Let $$$k_0$$$ and $$$k_1$$$ be the number of 0s and 1s in the final alternating string. Let $$$c_0$$$ and $$$c_1$$$ be the number of 0s and 1s we deleted.
Because our deletions must strictly alternate, the difference between the number of deleted 0s and 1s can be at most $$$1$$$. Thus, $$$|c_0 - c_1| \le 1$$$. We know that $$$c_0 = n_0 - k_0$$$ and $$$c_1 = n_1 - k_1$$$.
Let $$$\Delta n = n_0 - n_1$$$ and $$$\Delta k = k_0 - k_1$$$. Substituting our equations, the condition $$$|c_0 - c_1| \le 1$$$ translates to:
Since the final string is strictly alternating, $$$\Delta k$$$ can only be $$$-1$$$, $$$0$$$, or $$$1$$$. This means that if $$$|\Delta n| \gt 2$$$, it is mathematically impossible to satisfy the inequality, and we should output $$$-1$$$.
If it is possible ($$$|\Delta n| \le 2$$$), we want to maximize the length of our final string (which minimizes deletions). We can first greedily "compress" the initial string by removing all adjacent duplicate characters (e.g., 00011001 becomes 0101). Let the length of this compressed alternating string be $$$L$$$, and let $$$\Delta L$$$ be the difference between the number of 0s and 1s in it.
To ensure our sequence of deletions is valid, we must satisfy the condition $$$|\Delta n - \Delta k| \le 1$$$, meaning our final $$$\Delta k$$$ must be in the range $$$[\Delta n - 1, \Delta n + 1]$$$. We can safely remove any number of characters from the beginning or the end of our compressed alternating string, and it will remain alternating. Each character we remove shifts $$$\Delta L$$$ by exactly $$$+1$$$ or $$$-1$$$.
Thus, to fix the parity and enter the valid range, the minimum number of characters we must drop from the ends of our compressed string is exactly the mathematical distance from $$$\Delta L$$$ to the range $$$[\Delta n - 1, \Delta n + 1]$$$. This distance is exactly $$$\max(0, |\Delta n - \Delta L| - 1)$$$.
The total number of deleted characters is the number of characters removed during compression $$$(n - L)$$$, plus the characters removed from the ends to fix the parity. Final answer: $$$(n - L) + \max(0, |\Delta n - \Delta L| - 1)$$$.
Time complexity: $$$\mathcal{O}(n)$$$.
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
void solve() {
int n; cin >> n;
string s; cin >> s;
int n0 = 0, n1 = 0;
for (char c : s) {
if (c == '0') n0++;
else n1++;
}
int delta_n = n0 - n1;
if (abs(delta_n) > 2) {
cout << -1 << "\n";
return;
}
int L = 1;
int L0 = (s[0] == '0' ? 1 : 0);
int L1 = (s[0] == '1' ? 1 : 0);
for (int i = 1; i < n; i++) {
if (s[i] != s[i - 1]) {
L++;
if (s[i] == '0') L0++;
else L1++;
}
}
int delta_L = L0 - L1;
int ans = (n - L) + max(0, abs(delta_n - delta_L) - 1);
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}
2252C - Risky Tower
The tower collapses if all $$$m$$$ pieces of any single level are removed. This guarantees that the answer is at most $$$m$$$.
Let's write the condition to collapse a specific row $$$k$$$ via damage. The sum of destabilization factors of the removed pieces from rows $$$i \ge k$$$ must satisfy:
To satisfy this inequality using the minimum number of pieces, we must greedily select pieces with the largest $$$a_{i,j}$$$ from rows at and below $$$k$$$.
Since the answer will never exceed $$$m$$$, we only need to keep track of at most $$$m$$$ pieces at any time. We can process the grid from the bottom row ($$$n$$$) to the top row ($$$1$$$), maintaining a priority queue or sorted list of the largest $$$m$$$ destabilization factors $$$a_{i,j}$$$ seen so far.
At each row $$$k$$$, we insert its $$$m$$$ pieces into our active pool, discard all but the largest $$$m$$$ elements overall, and find the minimum number of largest elements that sum to at least $$$v_k$$$. The minimum number of pieces required across all rows $$$k$$$, bounded by $$$m$$$, is our answer.
Time complexity: $$$\mathcal{O}(n \cdot m \log m)$$$
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<long long> v(n + 1);
for(int i = 1; i <= n; i++) cin >> v[i];
vector<vector<long long>> a(n + 1, vector<long long>(m));
for(int i = 1; i <= n; i++) {
for(int j = 0; j < m; j++) {
cin >> a[i][j];
}
}
int min_ans = m;
vector<long long> best;
for(int k = n; k >= 1; k--) {
for(int j = 0; j < m; j++) {
best.push_back(a[k][j]);
}
sort(best.rbegin(), best.rend());
if ((int)best.size() > m) {
best.resize(m);
}
long long current_sum = 0;
int pieces = 0;
for(long long val : best) {
current_sum += val;
pieces++;
if (current_sum >= v[k]) {
min_ans = min(min_ans, pieces);
break;
}
}
}
cout << min_ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}
2252D - Array Replacement
Let's consider the difference array $$$d$$$, where $$$d_i = a_{i+1} - a_i$$$ for all $$$1 \le i \lt n$$$.
Consider what happens to the array $$$a$$$ when we perform an operation on index $$$i$$$. The triplet $$$(a_{i-1}, a_i, a_{i+1})$$$ becomes $$$(a_{i-1}, a_{i-1} - a_i + a_{i+1}, a_{i+1})$$$. Let's see how this affects our difference array $$$d$$$:
- The new $$$d_{i-1}$$$ becomes $$$(a_{i-1} - a_i + a_{i+1}) - a_{i-1} = a_{i+1} - a_i$$$, which is exactly the old $$$d_i$$$.
- The new $$$d_i$$$ becomes $$$a_{i+1} - (a_{i-1} - a_i + a_{i+1}) = a_i - a_{i-1}$$$, which is exactly the old $$$d_{i-1}$$$.
Thus, performing the operation on index $$$i$$$ is exactly equivalent to swapping $$$d_{i-1}$$$ and $$$d_i$$$!
However, we can only perform this operation if $$$a_{i-1}$$$ and $$$a_{i+1}$$$ have the same parity. Notice that $$$a_{i+1} - a_{i-1} = (a_{i+1} - a_i) + (a_i - a_{i-1}) = d_i + d_{i-1}$$$. For $$$a_{i-1}$$$ and $$$a_{i+1}$$$ to have the same parity, their difference $$$d_i + d_{i-1}$$$ must be an even number. The sum of two integers is even if and only if they have the same parity.
Therefore, the condition that $$$a_{i-1}$$$ and $$$a_{i+1}$$$ have the same parity is equivalent to saying $$$d_{i-1}$$$ and $$$d_i$$$ have the same parity.
This means we can swap any two adjacent elements in the difference array $$$d$$$ as long as they share the same parity. This allows us to independently sort any contiguous subsegment of $$$d$$$ that consists entirely of even numbers, or entirely of odd numbers.
To construct the lexicographically smallest array $$$a$$$, we simply group contiguous elements of $$$d$$$ that share the same parity, sort each group in non-decreasing order, and then reconstruct the array $$$a$$$ starting from $$$a_1$$$.
Time complexity: $$$\mathcal{O}(n \log n)$$$.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
void solve() {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<long long> d(n - 1);
for (int i = 0; i < n - 1; i++) {
d[i] = a[i + 1] - a[i];
}
for (int i = 0; i < n - 1; ) {
int j = i;
while (j < n - 1 && (d[j] & 1) == (d[i] & 1)) {
j++;
}
sort(d.begin() + i, d.begin() + j);
i = j;
}
cout << a[0] << " ";
long long cur = a[0];
for (int i = 0; i < n - 1; i++) {
cur += d[i];
cout << cur << " ";
}
cout << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}
2252E - Generational Triplets
From the arithmetic progression condition,
From the XOR condition,
Substituting the second equation into the first gives
Let $$$x$$$ be the bitwise AND of $$$a$$$ and $$$c$$$, i.e. x = a&c. Recall the standard bitwise addition identity
Therefore,
Equivalently, in bitwise notation, a^c = 2(a&c).
Thus, it is enough to count pairs $$$(a,c)$$$ such that $$$a \lt c \le n$$$ and a^c = 2(a&c).
For every such pair, $$$b$$$ is uniquely determined as $$$a \oplus c$$$. Also, $$$a \lt b \lt c$$$ follows from the two original conditions. We only need to enforce $$$a \lt c$$$: if $$$a=c$$$, then the equation becomes $$$0=2a$$$, which is impossible because $$$a \ge 1$$$.
We solve this with digit DP, processing bits from $$$60$$$ down to $$$0$$$. Let the state be
bit: the bit currently being processed.cLess: whether the already processed prefix of $$$c$$$ is strictly smaller than the corresponding prefix of $$$n$$$.aLess: whether the already processed prefix of $$$a$$$ is strictly smaller than the corresponding prefix of $$$c$$$.need: the value required for the current bit ofa&c, determined by the XOR value at the previous, more significant bit.
At each state, try all four choices for the current bits of $$$a$$$ and $$$c$$$. A transition is valid when:
- The chosen prefix of $$$c$$$ does not exceed the prefix of $$$n$$$.
- The chosen prefix of $$$a$$$ does not exceed the prefix of $$$c$$$.
- The current bit of
a&cequalsneed.
For the next lower bit, the new value of need is the XOR of the current bits of $$$a$$$ and $$$c$$$. This represents the one-bit left shift in a^c = 2(a&c).
After processing all bits, the state contributes $$$1$$$ exactly when need is $$$0$$$ and aLess is true, which guarantees $$$a \lt c$$$.
Time complexity: $$$\mathcal{O}(\log n)$$$ per test case.
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
long long dp[65][2][2][2];
long long n;
const int MOD = 1000000007;
long long solve_dp(int bit, int c_less, int a_less, int need) {
if (bit < 0) {
if (need == 0 && a_less == 1) return 1;
return 0;
}
if (dp[bit][c_less][a_less][need] != -1) {
return dp[bit][c_less][a_less][need];
}
long long ans = 0;
int n_bit = (n >> bit) & 1;
for (int a_bit = 0; a_bit <= 1; a_bit++) {
for (int c_bit = 0; c_bit <= 1; c_bit++) {
// Check constraint against n
if (c_less && c_bit > n_bit) continue;
// Check constraint a <= c (since we need a < c eventually)
if (!a_less && a_bit > c_bit) continue;
// Check the "need" condition for (a & c)
if (need == 1 && (a_bit & c_bit) == 0) continue;
if (need == 0 && (a_bit & c_bit) == 1) continue;
int next_c_less = c_less && (c_bit == n_bit);
int next_a_less = a_less || (a_bit < c_bit);
int next_need = a_bit ^ c_bit; // The next bit's & must match this bit's ^
ans = (ans + solve_dp(bit - 1, next_c_less, next_a_less, next_need)) % MOD;
}
}
return dp[bit][c_less][a_less][need] = ans;
}
void solve() {
cin >> n;
memset(dp, -1, sizeof(dp));
// Start at bit 60, c is constrained by n, a is not yet less than c, need = 0
cout << solve_dp(60, 1, 0, 0) << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}
2252F - Spectral Components
Let's solve the problem independently for a single color $$$c$$$ with $$$M$$$ vertices.
First, consider the case where $$$k = 1$$$. The optimal component is a single vertex, which mathematically corresponds to the centroid of the $$$M$$$ vertices. For any edge $$$e$$$ in the tree, let $$$m_{\mathrm{in}}[e]$$$ and $$$m_{\mathrm{out}}[e]$$$ be the number of color $$$c$$$ vertices on either side of the edge. The number of paths from color $$$c$$$ vertices that must cross edge $$$e$$$ to reach the centroid is exactly $$$w[e] = \min(m_{\mathrm{in}}[e], m_{\mathrm{out}}[e])$$$. Thus, the total distance to the centroid is:
where the sum is over all edges $$$e$$$ in the tree.
When $$$k \gt 1$$$, we must choose a connected component $$$S$$$ of $$$k$$$ vertices (which contains exactly $$$k - 1$$$ edges). Notice that if an edge $$$e$$$ is entirely inside $$$S$$$, no path from any colored vertex to $$$S$$$ needs to cross it (the distance is absorbed into the component). If an edge is outside $$$S$$$, exactly $$$w[e]$$$ paths still cross it. Thus, the cost of any valid component $$$S$$$ containing the centroid is:
To minimize $$$\mathrm{Cost}(S)$$$, we must maximize the sum of $$$w[e]$$$ for the $$$k - 1$$$ edges we pick. A crucial property of tree centroids is that $$$w[e]$$$ is monotonically decreasing as you move away from the centroid. Because of this monotonicity, if we simply greedily pick the $$$k - 1$$$ edges with the globally maximum $$$w[e]$$$ values in the entire tree, they are mathematically guaranteed to form a connected component containing the centroid!
However, calculating this naively for all colors takes $$$\mathcal{O}(N^2)$$$. To achieve the required time complexity, we process all colors using Virtual Trees (also known as Auxiliary Trees):
- For each color $$$c$$$, build a Virtual Tree of its $$$M$$$ vertices in $$$\mathcal{O}(M \log M)$$$ time using LCA.
- Run a bottom-up DP on the Virtual Tree to find $$$m_{\mathrm{in}}$$$ for each virtual subtree.
- A virtual edge $$$(u, v)$$$ represents a compressed path of $$$L = \operatorname{depth}[v] - \operatorname{depth}[u]$$$ real edges. Because there are no other vertices of color $$$c$$$ branching off this path, every single real edge on this path shares the exact same weight: $$$w' = \min(m_{\mathrm{in}}, m_c - m_{\mathrm{in}})$$$.
- For color $$$c$$$, collect the pairs (weight = $$$w'$$$, count = $$$L$$$) for all virtual edges.
- Sort these pairs by weight descending, and greedily pick up to $$$K - 1$$$ edges to subtract from the total sum of all $$$w[e]$$$.
Since the sum of sizes of all Virtual Trees over all colors is $$$\mathcal{O}(n)$$$, the overall time complexity is $$$\mathcal{O}(n \log n)$$$.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int LOG = 19;
int n;
vector<int> C, K;
vector<vector<int>> adj;
vector<int> tin, tout, depth;
vector<vector<int>> up;
int timer = 0;
void dfs(int v, int p, int d) {
tin[v] = ++timer;
depth[v] = d;
up[v][0] = p;
for (int i = 1; i < LOG; i++) {
up[v][i] = up[up[v][i - 1]][i - 1];
}
for (int u : adj[v]) {
if (u != p) dfs(u, v, d + 1);
}
tout[v] = ++timer;
}
bool is_ancestor(int u, int v) {
return tin[u] <= tin[v] && tout[u] >= tout[v];
}
int get_lca(int u, int v) {
if (is_ancestor(u, v)) return u;
if (is_ancestor(v, u)) return v;
for (int i = LOG - 1; i >= 0; i--) {
if (!is_ancestor(up[u][i], v)) u = up[u][i];
}
return up[u][0];
}
void solve() {
cin >> n;
C.assign(n + 1, 0);
K.assign(n + 1, 0);
adj.assign(n + 1, vector<int>());
tin.assign(n + 1, 0);
tout.assign(n + 1, 0);
depth.assign(n + 1, 0);
up.assign(n + 1, vector<int>(LOG, 1));
timer = 0;
vector<vector<int>> colors(n + 1);
for (int i = 1; i <= n; i++) {
cin >> C[i];
colors[C[i]].push_back(i);
}
for (int i = 1; i <= n; i++) cin >> K[i];
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1, 1, 0);
vector<long long> ans(n + 1, -1);
vector<int> cnt(n + 1, 0);
for (int c = 1; c <= n; c++) {
if (colors[c].empty()) continue;
int M_c = colors[c].size();
int K_c = K[c];
vector<int> nodes = colors[c];
sort(nodes.begin(), nodes.end(), [](int a, int b) { return tin[a] < tin[b]; });
int sz = nodes.size();
for (int i = 0; i < sz - 1; i++) {
nodes.push_back(get_lca(nodes[i], nodes[i+1]));
}
sort(nodes.begin(), nodes.end(), [](int a, int b) { return tin[a] < tin[b]; });
nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());
for (int u : colors[c]) cnt[u] = 1;
vector<int> st;
vector<pair<int, int>> vt_edges;
for (int u : nodes) {
while (!st.empty() && !is_ancestor(st.back(), u)) st.pop_back();
if (!st.empty()) vt_edges.push_back({st.back(), u});
st.push_back(u);
}
long long total_dist = 0;
vector<pair<long long, long long>> edge_weights; // {weight, count}
for (int i = (int)vt_edges.size() - 1; i >= 0; i--) {
int p = vt_edges[i].first;
int u = vt_edges[i].second;
cnt[p] += cnt[u];
long long w = min((long long)cnt[u], (long long)M_c - cnt[u]);
long long L = depth[u] - depth[p];
total_dist += w * L;
edge_weights.push_back({w, L});
}
sort(edge_weights.rbegin(), edge_weights.rend());
long long saved = 0;
long long needed = K_c - 1;
for (auto& ew : edge_weights) {
long long take = min(needed, ew.second);
saved += take * ew.first;
needed -= take;
if (needed == 0) break;
}
ans[c] = total_dist - saved;
for (int u : nodes) cnt[u] = 0;
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << (i == n ? "" : " ");
}
cout << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t; cin >> t;
while(t--) {
solve();
}
return 0;
}








A was too hard
its alright i guess
A was a bit tricky :(
By the 30th minute, I still couldn't solve A
I agree
I agree!!!
I agree
I agree.
i agree
l agree
A and B were challenging for a newbie like me! Great problems!
A and B were harder than C
E was easier than D
I agree
How would u come up with difference array in D?
Yeah I was somewhat wondering about this too. It took me like an hour to see it by which time I was unable to code up the solve. I was just looking at the sample cases and somewhat of throwing mental compute at it until a pattern emerged but I can't really see a way to naturally derive it. Perhaps its all in the algebra or you just had to pattern recognize.
In my opinion, I think this is a standard technique whenever the operations is about adjacent elements, A good starting point is to consider two ideas: Prefix sums & Difference arrays One of them would be 90% the invariant. This problem can be approached in a very similar way: 1110E - Magic Stones
I had seen this exact problem (Magic Stones) just a few days ago, so I went straight for the difference array approach. I could not solve Magic Stones on my first try.
I will try to explain for you my line of thoughts, I hope it helps. First, I begin to see when it is useful to apply the operation. This happens when $$$a_i \lt a_{i + 1} - a_i + a_{i - 1}$$$, which you can rearrange to be $$$a_i - a_{i - 1} \lt a_{i + 1} - a_i$$$. So from here I start considering the difference array $$$d_i = a_i - a_{i - 1}$$$ and try to see how doing an operation at index $$$i$$$ will affect our new array, $$$d$$$. It swaps $$$d_i$$$ and $$$d_{i + 1}$$$ and you can start translate all conditions and restrictions forced by the statement on the array $$$a$$$ to be new conditions on $$$d$$$ as done in the tutorial.
This is giga helpful, thanks for explaining your thought process
Thanks! I think this approach sounds really natural.
My thoughts on this: If you apply the operation twice to a certain aᵢ, it actually restores aᵢ, because aᵢ-1 + aᵢ+1 — (aᵢ-1 + aᵢ+1 — aᵢ) = aᵢ. This implies that aᵢ is possibly being swapped or something similar, so, taking the difference of the array is at least a direction worth trying. (And along the path you'll eventually find that di and di+1 are swapped) A similar approach also appears in some other problems, if I remember correctly.
How am I supposed to come up with the answer of D.
first you can see that every operation is reversable. then you can notice that what happens is that whatever the difference was to the left element, is now the difference to the right element, and vice versa. now you can rearrange the differences in continuous segments that all have the condition a[i-1]%2==a[i+1]%2 however you want. then its simply obvious that you want to sort these and apply the smallest first in order to have the lexicographically smallest possible result
Can someone give problems or advice on improving problems like B?
solve more binary string problems. this problem just uses a lot of common ideas that you can find in these problems.
Why does A and B were too hard?
Does anybody have alternate approaches or ideas as to how one would derive a solution for E?
Yes, first steps are same we need conclusion that a^c = 2(a&c). Then let's write a, c in two lines. This equation means that our table is built from three types of blocks (first line, second line) (0 1, 1 1) (1 1, 0 1) (0, 0) So now we built dp[size] — how many different tables with 2 x size table. This could get the answer for a, b, c where c is less than 2^log_2(n). Now we want to calclulate situation with c more than our bound. It means that we already know how the first two rows of the table are looking(it built from first or second block). And finally we get another dp, which means can we get prefix of number c using this blocks. Using this dp and the first one we look where will be first difference between c and n. 385993550
This is how I approached E ....
S(n) is number of all such triplets such that a<b<c<=n whose xor is 0 T(n) is number of such triplets such that c is n so, S(n) = T(n) + T(n-1) ..... T(1)
suppose n is such that n has more than 3 bits in binary representation( for n < 8 .... only T(3) =1 and T(6) is 1 , else all are zero)
suppose n = 2^k + 2^r + x ..... r < k, x < 2^r (if n is a perfect power of 2 ... T(n) = 0) since (k+1)th bit set we must choose b & c such that b have (k+1)th bit set and c does not. So b = 2^k + y ....... but we need 2*b — n < 2^k which implies 2y < x + 2^r ...... so y < 2^r
This would imply c = 2^r + z ..... (c need (r+1)th bit set and z<2^r) now we have 2b-n < 2^(r+1) ..... 2^k <= 2^k + 2y < 3.2^r + x < 4^r .... r > k-2 .... so r = k-1
So n = 2^k + 2^(k-1) + x , b = 2^k + y , c = 2^(k-1) + z ..... where x,y,z < 2^(k-1) also notice xor of n,b,c is zero if and only if xor of x,y,z is 0. 2b = n + c implies 2y = x + z
if x = y = z .... then they have to be 0. But otherwise we need not have x > y > z , x < y < z is also possible ..... But essentially we have a way to build all k bit solutions from all the pairs of <= k-2 bits .... we need to keep track of highest and lowest numbers of all triplets
p(k) is number of such triples such that highest number is k bit then ..... p(k) = 1 + 2*(p(2) + p(3) .... p(k-2))
1) lastly use induction to T(n) is either 1 or 0 2) Binary representation of all the n's such that T(n) = 1 and n is a k-bit number is of the form (111...111)(0)(any binary number) where starting 1 appears even number of times 3) c's corresponding to all above n are all (k-1) bit numbers and are of the form (111...1)(0)(any binary number) where starting 1's appear odd number of times
The condition in problem D had shown up before, in Problem 1110E. I wasn't able to solve it back when I tried that problem, but I immediately was able to recognize it in this contest. (edit: seems like it was already mentioned in this comment)
Also A and B were hard for me XD -- Here's how I did for the first half an hour:
Seeing even a Master turn out like this gives me peace of mind— I thought I was an idiot :(
I think there's an alternative approach to E: I'm not sure how to prove this, but a brute-force check indicated that the bit representations for a, b, c follow a pattern. The 64 bits can be broken into chunks of 1 or 2 bits:
I submitted a solution that recursively (+memoization) counts the number of ways in which such triplets (a, b, c) can be constructed, and it passes all test cases.
This representation is correct because a^c = 2(a&c) is true
D is insane, just guess and pray
Could you solve C by binary searching on the min threshold you take and then binary searching on how many times you take that threshold?
For E, answer = number of numbers between 3 and n such that if you write their binary representation, the first (most significant) consecutive group of ones has even length.
I kinda guessed this by brute force (shame on me), but it's quite an interesting result and it shouldn't be very hard to prove. Also, no dp or weird techniques, yay!
Submission: 385997563
A few interesting observations (assume n to be infinite here):
I might come back with a formal proof for the first two observations (or maybe someone else can comment one), the others being direct results of those two... but anyway, quite an interesting result :)
Yes, in order to get 2a&b= a xor b The main observation is that we should have above each 1 in both a and b, a 0 1 or 1 0 and vice versa
so if we consider that a<b, then look at the blocks of bits in b that are equal to 1, and look at the most significant bit and its block of ones, it must have an even size, since we must be able to split it into pairs so that in this pair we put a 0 then 1 below it in a. Then the other blocks of ones can have any size, if a block has an even size, we can just fill a with pairs of 01, otherwise we can put a 1 in a in the bit that is to 0 and above that block then alternate starting by 1
for example if b=[1111]000[111]0, then a=[0101]001[101]0, [] means a block of ones in b. So like this our condition will be verified
Elegant approach for Problem E: Let's try constructing a solution for $$$(a,b,c)$$$ bit by bit. Assume right now we have $$$(0,0,0)$$$, so the differences are $$$b-a = c-b = 0$$$.
We ask ourselves, what combinations of bits will maintain $$$b-a = c-b$$$? The options for combination are those that have either $$$0$$$ bits or $$$2$$$ bits: $$$(0,0,0), (1,1,0), (1,0,1), (0,1,1)$$$.
First, we must put $$$(0,1,1)$$$ because otherwise $$$a \lt b \lt c$$$ is not satisfied. Then, $$$b-a = 2^x$$$ and $$$c-b = 0$$$.
If we then put $$$(1,0,1)$$$, the differences turns into $$$b-a = 2^x-2^{x-1}=2^{x-1}$$$ and $$$c-b = 0+2^{x-1}$$$, so this is good and the equality is maintained after this combination: $$$(0,1,1),(1,0,1)$$$.
On the other hand, if we put $$$(0,1,1)$$$, $$$b-a = 2^x$$$ and $$$c-b = -2^{x-1}$$$ and there is no way any future moves can salvage this as their sum is at most $$$2^{x-1}-1$$$, so the best we can do is reduce the difference between $$$b-a$$$ and $$$c-b$$$ by $$$2\cdot (2^{x-1}-1)$$$, but the current difference is more than that. By similar logic, if we put $$$(1,1,0)$$$ we have $$$b-a = 2^x+2^{x-1}$$$ and $$$c-b = 0$$$ and no future moves can salvage this. If we put $$$(0,0,0)$$$, $$$b-a = 2^x$$$ and $$$c-b = 0$$$ and no future moves can salvage this since again, their sum can be at most $$$2^{x-2}$$$.
Thus, we've proven that whenever we do $$$(0,1,1)$$$, it must be immediately followed by a $$$(1,0,1)$$$, and that will maintain the equality, but if we put anything else, it will never maintain equality.
Now, assume that currently, the equality $$$b-a=c-b=e$$$ (for some $$$e$$$) is maintained, and we want to find a future combination of moves such that the equality is maintained again. We have just shown that $$$(0,1,1),(1,0,1)$$$ is a viable option and the only option if we ever decide to place down a $$$(0,1,1)$$$.
A similar proof can be used to show that whenever we put a $$$(1,1,0)$$$, it must always be followed by a $$$(1,0,1)$$$.
If we put down a $$$(0,0,0)$$$, this doesn't affect the equality, so we can do this as many times as we'd like.
Lastly, if we put down a $$$(1,0,1)$$$, the equality is $$$b-a = e-2^x$$$ and $$$c-b = e+2^x$$$. There is no way any future moves can salvage this as their max sum is $$$2^{x-1}-1$$$, so again we can at most reduce the difference by $$$2\cdot (2^{x-1}-1)$$$ but the current difference is $$$2 \cdot 2^x$$$, so it's more than that.
Thus, we've proven that the valid combinations we can place down are only $$$(0,0,0)$$$ or $$$(0,1,1)$$$ followed by $$$(1,0,1)$$$ or $$$(1,1,0)$$$ followed by $$$(1,0,1)$$$.
Now, what to do with this information? Since we only care that upper bound <= n, we look at the $$$c$$$ value. The options we see (based on above) are $$$0$$$, $$$11$$$, $$$01$$$ respectively. If we use these to construct $$$c$$$, then each of them perfectly match to a triplet based on the rules we created above, as all options are distinct and all have a different number of 1s, so perfect bijection.
More clearly, given a valid string constructed using these options, there is only one way to construct it: For every odd length $$$1$$$'s we are forced to construct this by putting a $$$01$$$ at the front followed by $$$11$$$'s, for every even length $$$1$$$'s we are forced to only put $$$11$$$'s. For the remaining $$$0$$$'s, we are forced to fill it with $$$0$$$'s. Thus, for every construction we are forced to construct it based on each block of consecutive $$$1$$$'s.
Other than the rule of "only using 3 options", we also note that in the beginning, it must start with a $$$11$$$. Thus, the problem turns into: "how many binary strings <= n can we construct such that it starts with $$$11$$$ and it uses only $$$11$$$, $$$01$$$, $$$0$$$?" Note given ANY string, if we ignore the prefix block of $$$1$$$s, then we can construct any odd length block of $$$1$$$s with a $$$01$$$ followed by $$$11$$$s, and a even length block of $$$1$$$s by just putting $$$11$$$s, and just fill the rest with $$$0$$$s since we can use it anytime we want. Thus, we turn our attention towards the prefix block of $$$1$$$s. We can only place down $$$11$$$s, and not $$$01$$$s, so the prefix block of $$$1$$$s. Must be even length. This is the only constraint. Thus, the problem then turns into "how many binary strings <= n such that it starts with a even number of consecutive $$$1$$$s before the first $$$0$$$".
This can be easily solved by brute forcing all lengths of binary strings, then brute forcing over all even length prefixes of $$$1$$$s. We then place a $$$0$$$ after, then the remaining string can be whatever combination we want (we can construct any string using $$$11$$$, $$$01$$$, $$$0$$$ by above strategy). Thus anything from $$$0$$$ to $$$2^k-1$$$ (for some $$$k$$$) is possible.
For example, consider if our length is $$$x$$$ and our prefix length is $$$y$$$ (where $$$y$$$ is even). Then, the prefix of $$$1$$$'s is $$$(2^y-1) \cdot (2^{x-y})$$$ and $$$k = x-y-1$$$ so we can have everything from $$$0$$$ to $$$2^k-1$$$ as suffix. Here, we can easily handle the overflow case by just taking the minimum of $$$n$$$ without the prefix ($$$y$$$ $$$1$$$s at the front), and the suffix we can obtain. That is, we take $$$min(n-(2^y-1) \cdot (2^{x-y})+1, 2^{x-y-1})$$$.
Submission
came up with the same idea just wasnt able to find out closed form
No idea why I got disliked, just say yall got a herd mentality T_T
orz
There could be a harder version of C where the problem becomes a bit more sophisticated. Basically it would be the same C problem but the jenga wouldn’t collapse if you take M elements from a level. So basically the problem would be like The tower collapses if the condition is met, the stability of index i drops to 0 or less, if it is not possible output -1.
It can be solved with Co-ordinate compression + segment tree with binary search at each n, giving us a total time complexity of n*log^2(n*m). That's the code i solved C which was pretty inefficient for this specific problem but it works.
I overcomplicated the problem in a similar way. But you don't need a segment tree for something like that right? I think my submission will also work if you tweak my binary search in function solve() a bit.
Basically the idea is exactly like the editorial, except I binary searched the answer and stored the corresponding amount in the priority queue in each layer as a check function. Then I would have the sum of the biggest k elements at each layer and able to get answer. Answer is pretty slow so might need some extra optimizations.
Refer to submission: 385939195.
Great Solution! Liked it.
interesting solution
I wrote same solution : 386022122 But It passed 2x faster than yours. Only difference is just ->
A is hard for me TAT
I did B with DP. Mainly the same idea as the first part of editorial, but after counting the number of ones and zeros in the entire string, I use dp to find the longest alternating subsequences of the following conditions:
(Additionally, let D[i] = #ones — #zeros in subsequence i)
starting with 0, ending with 0 (0b00) (D[0b00] = -1)
starting with 0, ending with 1 (0b01) (D[0b01] = 0)
starting with 1, ending with 0 (0b10) (D[0b10] = 0)
starting with 1, ending with 1 (0b11) (D[0b11] = 1)
Now, imagine keeping one of these subsequences j and removing everything that was not in that subsequence. The difference between the removed ones and the removed zeros is equal to:
(#ones in entire string — #ones in subsequence) — (#zeros in entire string — #zeros in subsequence)
= #ones in the entire string — #zeros in the entire string — D[j],
and if its absolute value is less than or equal to 1, then we let this alternating sequence contribute. Sorry for my poor writing. My submission 386004241 might be helpful.
Emm, I wrote a Fenwick Tree to solve C in time complexity O(nmlog^2(nm)), still WA and unable to hack my code......
A is too hard.It tooks me about 20 minutes.
There's a solution without attention for problem E.
We use binary digit DP. Let $$$f[i][d][p][q]$$$ be the number of assignments for the lowest $$$i$$$ bits such that $$$a+c-2b=d\cdot2^i$$$, where $$$p$$$ and $$$q$$$ indicate whether the lower bits are required to satisfy $$$a \lt b$$$ and $$$b \lt c$$$. When adding new highest bits $$$x,y,z$$$, we require $$$x\oplus y\oplus z=0$$$, and the new carry is $$$(d+x+z-2y)/2$$$. We then scan the bits of $$$n$$$ from high to low while keeping the prefix of $$$c$$$ equal to the prefix of $$$n$$$, together with the required carry and whether $$$a \lt b$$$ and $$$b \lt c$$$ have already been determined. When the current bit of $$$c$$$ becomes smaller than the corresponding bit of $$$n$$$, the remaining lower bits are unrestricted and can be counted directly using $$$f$$$. Finally, we add the state where $$$c=n$$$, the carry is zero, and both inequalities are strict. The complexity is $$$O(\log n)$$$ per test case.
You can find my implementation here : 385956802.
In which world A and B are supposed to be easy.
Thansk for aditorial
I succeed in doing ABC. :)
Why many prople says A is hard?
A is easy.Reasons:
1. It's the only one problem what close the solution submission channel.
2. You can think that make all the cards in a row different,so you should put card what more first.
But it's a greedy round.The problems are all have greedy tag expect E. :<
Don't use segment tree in C!Or you will MLE on pretest 3.
C was easier than B.
in problem A, I think one of the edge case is missing in the given editorial and the solution.
when their are multiple values which have the same max_frq then, which value is need to be considered as 'X'?. It must the be the min_value from all the values whose frq is same as max_frq.
Why min_value need to consider as 'X'? because all 'X' can be taken or maybe some dropped, if we need to drop some 'X', then considering min_value for 'X' is better choise.
but editorial didn't specified this, and the solution consider 'X' value as any value whose frq is max_frq.
I don't think choosing the minimum value among all maximum-frequency values is necessary.
Let the maximum frequency be $$$f$$$. If there are at least two distinct values with frequency $$$f$$$, then
Hence, no value appears more than $$$\left\lfloor\frac{n}{2}\right\rfloor$$$ times. Under this condition, the elements can always be arranged by interleaving, regardless of which maximum-frequency value is chosen as $$$X$$$.
So I don't see why the smallest value among all maximum-frequency values must be selected. It seems that any value with maximum frequency should work.
Ah, I see it now! That’s a really neat observation & proof— the case I was worried about is actually never a issue. I was treating it as a valid edge case without first checking whether it was reachable.
CF problems are evolving it seems.
why this code doesn't work for C.
good contest
I think my code is wrong/has some logical error for A but passed due to incorrect test cases
My approach:
first i took a map to find the freq array
then made a pair as {freq,damage}
sorted them
then used 2 pointer on first and last one to add dmg alternatively
It should fail on [(5,10),(4,9),(4,8)]-->{freq,dmg}
I think there is an error in test cases or missing
This is my code : 385926129
There is any other approach for A?
Using priority queue you can pick most frequent element and keep track of previous element and pick element from priority which is not previous element and update previous element.
can brainlessly simulate the process : submission
my approach is easy to understand 386052487
yeah
is there any dp approach for B ?
anyone who hasn't figured the solution of B.
Yay !
In problem B's editorial, how does the solution make sure that the characters are deleted alternatively?
A is very similar to the problem task scheduler in leetcode , you could read their editorial for better understanding and other alternative approaches like pq