B turned out to be harder than expected. I apologize for this, but I hope there are still problems that are fun and educational for you to solve in this round.
Regardless, I hope this round encourages authors to include communication problems in their future rounds, and in earlier positions as well.
Problem A — Souvlaki VS. Kalamaki
Suppose it Kalamaki's turn on some even round $$$2k$$$. Kalamaki can swap element $$$a_{2k}$$$ with $$$a_{2k+1}$$$. If $$$a_{2k} \gt a_{2k+1}$$$, he will not swap the elements, but if $$$a_{2k} \lt a_{2k+1}$$$, he will swap them. In both cases he wins the game, because the array will never be sorted. Therefore, if $$$a_{2k} \neq a_{2k+1}$$$, Kalamaki will win no matter what.
Now assume every time Kalamaki plays, the two elements he can swap have the same value, because otherwise we have shown that he wins. Suppose that it is Souvlaki's turn on round $$$2k+1$$$. We know that $$$a_{2k} = a_{2k+1}$$$ from the previous assumption. If $$$a_{2k+1} \gt a_{2k+2}$$$, we know that $$$a_{2k+1} = a_{2k} \gt a_{2k+2}$$$, but he is unable to swap $$$a_{2k}$$$ and $$$a_{2k+2}$$$, therefore he loses. Otherwise, if $$$a_{2k+1} \le a_{2k+2}$$$ he will not do anything, and he proceeds to the next round.
From these observations, we see that $$$a$$$ is winnable by Souvlaki if and only if: $$$a_1 \le a_2 = a_3 \le a_4 = a_5 \le \ldots$$$, or $$$a_2 \le a_1 = a_3 \le a_4 = a_5 \le \ldots$$$. It is obvious now that Souvlaki, before the start of the game, will sort $$$a$$$ in non-decreasing order. To determine if Souvlaki wins or not it is enough to check the above condition is satisfied after sorting.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n; cin >> n;
int a[n+1];
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a+1, a+n+1);
for (int i = 2; i <= n - 1; i+=2) {
if (a[i] != a[i+1]) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
int main() {
int t; cin >> t;
while (t--) solve();
return 0;
}
Let the position of integer $$$x$$$ in the permutation $$$p$$$ be denoted by $$$pos_x$$$.
Let's see for which indices $$$i$$$ we can never set $$$s_i$$$ to $$$1$$$, even with an infinite number of operations. First of all, in an operation $$$(l, r)$$$, we only consider indices $$$i$$$ such that $$$l \lt i \lt r$$$. This means that we can never set $$$s_1$$$ or $$$s_n$$$ to $$$1$$$. In addition, we only consider indices $$$i$$$ such that $$$p_i$$$ is between $$$p_l$$$ and $$$p_r$$$, but not equal to those. This means that we can never set $$$s_{pos_1}$$$ or $$$s_{pos_n}$$$ to $$$1$$$. In general, if $$$x_1 = 1$$$, $$$x_n = 1$$$, $$$x_{pos_1} = 1$$$, or $$$x_{pos_n} = 1$$$, it is impossible to solve the problem.
Now I will show that the problem is always solvable for any binary string $$$x$$$ such that $$$x_1 = x_n = x_{pos_1} = x_{pos_n} = 0$$$, within $$$5$$$ operations.
WLOG, assume $$$pos_1 \lt pos_n$$$. It is natural to think about using $$$pos_1$$$ and $$$pos_n$$$ as endpoints for our operations. For example, by using the operations $$$(1, pos_1)$$$ and $$$(1, pos_n)$$$, we will have set $$$s_i = 1$$$ for every $$$1 \lt i \lt pos_1$$$. Likewise, with the operations $$$(pos_1, n)$$$ and $$$(pos_n, n)$$$, we will have set $$$s_i = 1$$$ for every $$$pos_n \lt i \lt n$$$. By using the operation $$$(pos_1, pos_n)$$$, we have set $$$s_i = 1$$$ for every $$$pos_1 \lt i \lt pos_n$$$.
With these $$$5$$$ operations, we have finally set $$$s_i = 1$$$ for every $$$i$$$ in $$$(1, pos_1) \cup (pos_1, pos_n) \cup (pos_n, n)$$$, which guarantees we have solved the problem.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n; cin >> n;
vector<int> a(n+1);
int mn = 1, mx = 1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] < a[mn]) mn = i;
if (a[i] > a[mx]) mx = i;
}
string t; cin >> t;
t = " " + t;
if (t[1] == '1' || t[n] == '1') {
cout << -1 << "\n";
return;
}
if (t[mn] == '1' || t[mx] == '1') {
cout << -1 << "\n";
return;
}
cout << 5 << "\n";
cout << 1 << " " << mn << "\n";
cout << 1 << " " << mx << "\n";
cout << mn << " " << n << "\n";
cout << mx << " " << n << "\n";
cout << min(mn, mx) << " " << max(mn, mx) << "\n";
}
int main() {
int t; cin >> t;
while (t--) solve();
return 0;
}
We call a pair of integers $$$(l, r)$$$ good if and only if $$$1 \le l \le r \le 2n$$$ and in $$$f(l, r)$$$ there is a down-right path from $$$(1, 1)$$$ to $$$(2, n)$$$ of cells with value of $$$1$$$. For some fixed left endpoint $$$l$$$ from $$$1$$$ to $$$2n$$$, let $$$r_l$$$ denote the minimum integer such that the pair $$$(l, r_l)$$$ is good. If there does not exist such an integer, for convenience we say $$$r_l = n+1$$$.
The first observation is that if $$$(l, r)$$$ is good, and $$$r \lt 2n$$$, then $$$(l, r+1)$$$ is also good. The reason is obvious: every cell that has value of $$$1$$$ in $$$f(l, r)$$$ has value of $$$1$$$ in $$$f(l, r+1)$$$. Therefore, if we find $$$r_1, r_2, \ldots, r_{2n}$$$, the answer will be $$$(2n - r_1 + 1) + (2n - r_2 + 1) + \ldots + (2n - r_{2n} + 1)$$$. (In other words, we are counting all pairs $$$(l, r_l), (l, r_l+1), \ldots, (l, 2n)$$$, for all $$$1 \le l \le 2n$$$).
The second observation follows: $$$r_1 \le r_2 \le \ldots \le r_{2n}$$$. It is clear that the only difference between grids $$$f(l, r_l)$$$ and $$$f(l+1, r_l)$$$ is that $$$f(l+1, r_l)$$$ has the same or a greater amount of cells with value of $$$0$$$, and if some cell has value of $$$1$$$ in $$$f(l+1, r_l)$$$, it has value of $$$1$$$ in $$$f(l, r_l)$$$. If we do not have a down-right path anymore in $$$f(l+1, r_l)$$$, there is no down right path in any $$$f(l+1, r)$$$ with $$$r \le r_l$$$. It follows that $$$r_{l+1} \ge r_l$$$.
This observation allows us to use two pointers. For some fixed $$$l$$$ and $$$r$$$, if $$$(l, r)$$$ is not good, we will keep increasing $$$r$$$ until it is good, or in other words find $$$r_l$$$. We activate all cells with value of $$$r+1$$$. To check if the pair $$$(l, r+1)$$$ is good, we get the first de-activated cell in the first row and the last de-activated cell in the last row (a cell is de-activated if it does not belong in the range we are currently considering). This can be done by keeping two sets of de-activated cells, one for each row. Suppose that those are at columns $$$a$$$ and $$$b$$$ respectively. There exists a down-right path in $$$f(l, r+1)$$$ if and only if $$$a - 1 \gt b$$$ (we can reach cell $$$(1, a-1)$$$, then go to cell $$$(2, a-1)$$$ and the proceed to $$$(2, n)$$$). Once we find $$$r_l$$$, we will increase $$$l$$$, de-activate every cell with value of $$$l$$$, and keep increasing $$$r_l$$$ until we find $$$r_{l+1}$$$, and so on.
// nifeshe
#ifdef LOCAL
#include <bits/include_all.h>
#else
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#endif
#pragma GCC target ("avx2")
#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("unroll-loops")
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define int long long
using namespace std;
using namespace __gnu_pbds;
template <typename T> using oset = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T> inline bool umin(T &a, const T &b) { if(a > b) { a = b; return 1; } return 0; }
template <typename T> inline bool umax(T &a, const T &b) { if(a < b) { a = b; return 1; } return 0; }
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const ll mod = 998244353;
const ll inf = 1e18;
const int MAX = 2e5 + 42;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<ll> dis(1, inf);
void solve() {
int n;
cin >> n;
vector<vector<int>> a(2, vector<int>(n));
for(auto &i : a) {
for(auto &j : i) {
cin >> j;
}
}
vector<vector<pii>> pos(2 * n + 1);
for(int i = 0; i < 2; i++) {
for(int j = 0; j < n; j++) {
pos[a[i][j]].push_back({i, j});
}
}
array<set<int>, 2> st;
st[0].insert(inf);
st[1].insert(-inf);
for(int i = 0; i < n; i++) st[0].insert(i);
for(int i = 0; i < n; i++) st[1].insert(i);
auto add = [&](int x) {
for(auto [i, j] : pos[x]) {
st[i].erase(j);
}
};
auto del = [&](int x) {
for(auto [i, j] : pos[x]) {
st[i].insert(j);
}
};
auto check = [&]() {
if(st[0].count(0)) return false;
if(st[1].count(n - 1)) return false;
if(*st[0].begin() - 1 <= *st[1].rbegin()) return false;
return true;
};
int ans = 0;
int r = 0;
for(int l = 1; l <= 2 * n; l++) {
while(r + 1 <= 2 * n && !check()) {
add(++r);
}
if(!check()) break;
ans += 2 * n - r + 1;
del(l);
}
cout << ans << '\n';
}
signed main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int ttt = 1;
cin >> ttt;
while(ttt--) {
solve();
}
}
Problem D1 — Diadrash (Easy Version)
First, observe that if a range is completely inside another, it is useless. Specifically, assume we have two ranges $$$[l_1, r_1]$$$ and $$$[l_2, r_2]$$$. If $$$1 \le l_2 \le l_1 \le r_1 \le r_2 \le n$$$, then we know that $$$\operatorname{MEX}(p[l_1 \ldots r_1]) \le \operatorname{MEX}(p[l_2 \ldots r_2])$$$. So we must only consider the range $$$[l_2, r_2]$$$.
After cleaning out those ranges, we are left with at most $$$n$$$ ranges. This is obvious because for every possible left endpoint, we have at most one possible right endpoint (the maximum one among all given ranges).
Now, suppose we also knew the position of $$$0$$$. Let it be $$$p_0$$$. We know that if some range does not include $$$p_0$$$, it is also useless. I claim that removing these ranges leaves at most $$$\lceil \frac{n}{2} \rceil$$$ possible ranges we must consider. Specifically, if $$$p_0 \le \frac{n}{2}$$$, we only consider ranges with left endpoint before than $$$p_0$$$. Otherwise, if $$$p_0 \ge \frac{n}{2}$$$, we only consider ranges with right endpoint after $$$p_0$$$. In both cases, it is obvious we consider at most $$$\lceil \frac{n}{2} \rceil$$$ ranges.
Finally, notice that we do not care about the exact value of $$$p_0$$$, but only if it is in the first half or the second half. Therefore, we will do a query of the form $$$[1, \frac{n}{2}]$$$, determine which half $$$p_0$$$ is in, clean out useless ranges and query the rest. This results to at most $$$\lceil \frac{n}{2} \rceil + 1$$$ queries, and the problem is solved.
#include <bits/stdc++.h>
using namespace std;
int LIM, Q;
int ask(int l, int r) {
Q++;
assert(Q <= LIM);
cout << "? " << l << " " << r << endl;
int ans; cin >> ans;
return ans;
}
bool inside(int l, int r, bool toL, int n) {
int midL = n / 2;
if (toL) {
return l <= midL;
}
else return r > midL;
}
void solve() {
int n, q; cin >> n >> q;
Q = 0;
LIM = max(30, n / 2 + n % 2 + 5);
vector<int> maxR(n+1, 0);
for (int i = 1; i <= q; i++) {
int l, r; cin >> l >> r;
maxR[l] = max(maxR[l], r);
}
bool toL = (ask(1, n/2) > 0);
int ans = 0, mx = 0;
for (int i = 1; i <= n; i++) {
if (maxR[i] > mx && inside(i, maxR[i], toL, n)) {
ans = max(ans, ask(i, maxR[i]));
}
mx = max(mx, maxR[i]);
}
cout << "! " << ans << endl;
}
int main() {
int t; cin >> t;
while (t--) solve();
return 0;
}
Problem D2 — Diadrash (Hard Version)
Special thanks to Friedrich for figuring out the better solution.
Please read the first two paragraphs of the solution to the Easy Version first. Suppose we have cleaned out the ranges that are completely inside other ranges.
A useful property to consider, is that for a range $$$[l, r]$$$ it holds that $$$\operatorname{MEX}(p[l...r]) = \min(\operatorname{MEX}(p[1...r]), \operatorname{MEX}(p[l...n]))$$$. To prove this, consider the first non-negative integer $$$k$$$ such that it does not appear in $$$p[l...r]$$$. In other words, $$$\operatorname{MEX}(p[l...r]) = k$$$. If $$$k$$$ appears to the left of the range, we have $$$\operatorname{MEX}(p[1...r]) \gt k$$$ and $$$\operatorname{MEX}(p[l...n]) = k$$$. Otherwise, we have $$$\operatorname{MEX}(p[1...r]) = k$$$ and $$$\operatorname{MEX}(p[l...n]) \gt k$$$. In both cases, it holds $$$k = \operatorname{MEX}(p[l...r]) = \min(\operatorname{MEX}(p[1...r]), \operatorname{MEX}(p[l...n]))$$$.
Consider a set of ranges $$$S$$$, such that no range is completely inside another. Picking a range $$$[l, r]$$$ of this set splits $$$S$$$ to two subsets: one set $$$L$$$ includes all ranges $$$[l_1, r_1]$$$ such that $$$l_1 \lt l$$$, and the other set $$$R$$$ includes all ranges $$$[l_2, r_2]$$$ such that $$$l \lt l_2$$$. If we could find the best subset to keep searching in depending on $$$[l, r]$$$, we could perform binary search and find the answer quickly.
So we now have the subproblem: given a range $$$[l, r]$$$, figure out if the oprimal subset to search is $$$L$$$ or $$$R$$$. We will use the following properties:
- $$$\operatorname{MEX}(p[1...i]) \le \operatorname{MEX}(p[1...i+1])$$$.
- $$$\operatorname{MEX}(p[i+1...n]) \le \operatorname{MEX}(p[i...n])$$$.
- $$$\operatorname{MEX}(p[l...r]) = \min(\operatorname{MEX}(p[1...r]), \operatorname{MEX}(p[l...n]))$$$
Suppose $$$a = \operatorname{MEX}(p[1...r])$$$ and $$$b = \operatorname{MEX}(p[l...n])$$$. If $$$a \lt b$$$, we have no reason to go to $$$L$$$. This is because the prefix $$$\operatorname{MEX}$$$ will keep decreasing, but the suffix $$$\operatorname{MEX}$$$ will keep increasing, so we will always pick the prefix which is definitely not as great as the current $$$a$$$. Therefore, we will move to $$$R$$$. Likewise, if $$$a \gt b$$$, we will move to $$$L$$$. Note that the case $$$a = b$$$ is only possible if $$$[l..r] = [1...n]$$$, in which case the answer is $$$n$$$.
Therefore, for each range we consider we make $$$2$$$ queries, and we do this with binary search at most $$$\log{n}$$$ times. We have solved the problem in $$$2\log{n}$$$ queries.
#include <bits/stdc++.h>
using namespace std;
#define int long long
int ask(int l, int r) {
cout << "? " << l << " " << r << endl;
int ans; cin >> ans;
return ans;
}
void solve() {
int n, q; cin >> n >> q;
vector<int> maxR(n+1, -1);
for (int i = 1; i <= q; i++) {
int u, v; cin >> u >> v;
maxR[u] = max(maxR[u], v);
}
vector<pair<int, int>> ranges;
int mr = 0;
for (int i = 1; i <= n; i++) {
if (maxR[i] > mr) {
mr = maxR[i];
ranges.push_back({i, maxR[i]});
}
}
q = ranges.size();
int lo = 0, hi = q-1;
int ans = 0;
while (lo <= hi) {
int mid = (lo + hi) / 2;
int l = ranges[mid].first;
int r = ranges[mid].second;
int pref = ask(1, r);
int suff = ask(l, n);
ans = max(ans, min(pref, suff));
if (pref > suff) {
hi = mid-1;
}
else lo = mid+1;
}
cout << "! " << ans << endl;
}
signed main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t; cin >> t;
while (t--) solve();
return 0;
}
First, we consider an easier version of the problem: what if every cell of the first column had the same value?
Suppose that every cell of the first column has value of $$$1$$$. We have the following information:
- No matter which row Player A sends, the first cell of that row has value of $$$1$$$.
- Player A has the choice of sending a column full of $1$s.
- If $$$C = 0$$$, there exists a cell with value of $$$0$$$. ($$$C = 0$$$ and every cell having value of $$$1$$$ is a contradiction).
This information leads us to the following strategy. If $$$C = 1$$$, Player A may send any row and the first column. Otherwise, if $$$C = 0$$$, he can send any row and find a column that has a $$$0$$$ in it. Then, Player B can simply compare the first cell of the row with every cell of the column; if they all match, the answer is $$$1$$$, and otherwise it is $$$0$$$.
If every cell of the first column is $$$0$$$, the solution is the same. Note there must exist at least one $$$1$$$ in the grid, as mentioned in the statement (connectivity would not be well defined otherwise). So if $$$C = 0$$$ Player A sends any row and the first column, and otherwise if $$$C = 1$$$ he sends any row and finds a column which includes a $$$1$$$. Again, Player B will compare the value of the first cell of the row with the value every cell of the column, and if they match he answers $$$0$$$ and $$$1$$$ otherwise.
Now we can generalize this solution the case where there exists both a $$$0$$$ and a $$$1$$$ in the first column. Player B always compares the first cell of the row he received: if there exists a cell with different value in the column he determines the answer is the opposite of the value of the first cell of the row. We know the following:
- Player A can send a column with both a $$$0$$$ and a $$$1$$$ (The first column).
- Player A can choose a row, such that its first cell has value $$$0$$$.
- Player A can choose a row, such that its first cell has value $$$1$$$.
Therefore, Player A can always choose the first column and the appropriate row according to $$$C$$$ such that the previous strategy still works for Player B.
#include <bits/stdc++.h>
using namespace std;
int ask(vector<vector<bool>> &grid, vector<pair<int, int>> arr, int op) {
int ans = 0;
if(op==0) ans=1;
for (auto [a, b]: arr) {
if(op) ans=ans||grid[a][b];
else ans=ans&&grid[a][b];
}
return ans;
}
void ans(bool x) {
cout << x << endl;
}
int find_row(vector<vector<bool>> &grid, int need, int n) {
int lo = 1, hi = n;
int fin = 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
vector<pair<int, int>> qr;
for (int i = 1; i <= mid; i++) qr.push_back({i, 1});
if (need == ask(grid, qr, need)) {
fin = mid;
hi = mid-1;
}
else lo = mid+1;
}
return fin;
}
int find_col(vector<vector<bool>> &grid, int need, int n) {
int lo = 1, hi = n;
int fin = 1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
vector<pair<int, int>> qr;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= mid; j++) {
qr.push_back({i, j});
}
}
if (need == ask(grid, qr, need)) {
fin = mid;
hi = mid-1;
}
else lo = mid+1;
}
return fin;
}
void send_grid() {
int n; cin >> n;
bool ans; cin >> ans;
vector<vector<bool>> grid(n+1, vector<bool>(n+1));
for(int i = 0; i < n; i++) {
string s;
cin >> s;
for(int j = 0; j < n; j++) if(s[j]=='1') grid[i+1][j+1]=1;
}
vector<pair<int, int>> qr;
for (int i = 1; i <= n; i++) {
qr.push_back({i, 1});
}
int o = ask(grid, qr, 1), a = ask(grid, qr, 0);
int col, row;
if (o == 1 && a == 0) {
col = 1;
row = find_row(grid, !ans, n);
}
else if (o == 0) {
row = 1;
if (ans == 0) col = 1;
else col = find_col(grid, 1, n);
}
else {
row = 1;
if (ans == 1) col = 1;
else col = find_col(grid, 0, n);
}
cout << row << " " << col << endl;
}
void receive_grid() {
int n; cin >> n;
string row,col;
cin >> row >> col;
bool diff = false;
for (int i = 0; i < n; i++) {
if (col[i] != row[0]) diff = true;
}
if (diff) {
ans(!(row[0]=='1'));
}
else {
ans((row[0]=='1'));
}
}
void solve() {
string run; cin >> run;
int t; cin >> t;
if (run == "first") for (int i = 1; i <= t; i++) send_grid();
else for (int i = 1; i <= t; i++) receive_grid();
}
int main() {
int t = 1;
while (t--) solve();
return 0;
}









first.
B is too hard for div2
B is very easy greedy, if you account for the cases where it is impossible to make certain(upto 4) positions 1 then you can just make the rest of the entire string 1 with maximum 5 operations. Just greedily select
1) 0 index and min
2) 0 index and max
3) min and last index
4) max and last index
5) 0 index and last index
I agree. This also discourages participants. Because some may think if B is such hard, then how much hard the others will be!
Bad contest
B is the worst problem
I hate the trend of C being easier than B..
100% agreed. it just waste the time that could be utilized in the C (T_T).
If only I have seen C before B :(. I spent a lot of time on B, and still couldn't solved
it's happened in three latest contents, and that's weird.
Yes,i also find out that the three latest contest's B are wired,and i'm really not benifited to solve these questions
Mistaken order of B and C will eat my huge rating:(
Ok, over all Bs difficulty mostly comes from the strange statement. At first, I was sure that $$$\max (p_l, p_r)$$$ referred to the whole range. But once you realize that it is not the case, then the following observations really help:
And then you ask yourself, since I have those elements that can never be one, can I use them to create ranges that are able to create everything else? And the answer is yes!
That feel like pure guessing. I got the four observations you listed almost immediately, still couldn't solve it but coming up with false greedy solutions.
How to be good at this kind of problems?
Uhhh, I think that's kinda the point of codeforces... There are a lot of problems that require knowing how and where to guess.
I personally find that there are a lot of easy problems that are sometimes surprisingly tricky. I remember like a year ago I found a 1200 rated problem that just killed me: I had NO idea how to solve it in any reasonable way.
So I think that overall to get better at them... well... just do more problems xd
Although perhaps it could make sense to actually sort problems in the range 1000 to 1800 by least solved, and perhaps then you can find problems that are surprisingly annoying/weird/etc
Maybe I really should do more CF problems :P
I never thought of that, will try it someday. Thanks!
It's not really guessing of you instead consider a certain element and try to make it one, you will notice immediately it's impossible when it's a min or max, then that it can't be on the edges of the array. The argument for why it's impossible to turn these into ones naturally leads you to why it's possible to do that for the others. Finally you notice that there are 5 interesting ranges ( combining edges of the array and min/max ) that turn everything else into one.
Could you please explain your initial approach in simpler words, it is somewhat difficult to understand for a newbie. Would mean a lot
So for me, it was kinda like pattern recognition... I made those four observations and asked myself if, since they can never be painted, maybe they're the only ones that can never be painted and that I can paint all the others in at most 5 operations.
And so I actually took out my notebook and started drew out the borders, after which I connected them all and got 5 meaningful ranges.
I'm afraid I can't go much more in-dept than that... I recommend that you focus on lower rated problems for now so as to be able to more easily attempt these kinds of problems >:)
Ahhhh, I forgot that the elements in p are unique
B will take me to newbie
the solution of B is good learning something new
after seeing the soln b seems awesome; if only i had figured that out in contest ; hopefully i would be able to solve similar problems in future contest
ok, thanks for quick editorial.
I got cooked by
BProblem B:
What is the meaning of hold at the same time ?
My Interpretation : If any only if for all i , sunch that l<i<r , min(pl,pr)<pi<max(pl,pr) ?
You got it right:
∀l,r ∈ ℤ (1 ≤ l ≤ r ≤ n ∧ ∀i ∈ ℤ (1 ≤ i ≤ n ∧ l < i < r ∧ min(p[l],p[r]) < p[i] < max(p[l],p[r]) ⇒ s[i] = 1))Can anyone tell me what's wrong with my solution for C? 348365560
Hey,
Were you able to figure out why this fails? I had the same approach
No
E: Let $$$r,c$$$ the input for the second run (both are binary strings with length of $$$n$$$).
We can construct such input at the first run.
This is indeed a correct alternative solution for problem E
Whats the proof that you can always construct such input at the first run?
Suppose every column and row satisfy $$$r \gt c$$$ and $$$C=1$$$,
Choose any $$$c$$$ which has at least one
1, consider row $$$1$$$. It should have at least one1. Then, we got a column with first element is1. As a result, the first column will be full of1. No row can be greater than this column.Suppose every column and row satisfy $$$r\leq c$$$ and $$$C=0$$$,
Choose any $$$r$$$ which has at least one
1, consider column $$$1$$$. It should have at least one1. Then, we got a row with first element is1. As a result, the first row will be full of1, and every column is full of1, and the connectivity is $$$1$$$ now.it seems like a proof by contrast. but I still don't get it. can you please elaborate on how the connectivity is related to the row and column dictionary order please?
As mentioned above, there're no binary grid that satisfy every $$$r \gt c$$$. And the only $$$2$$$ binary grid that satisfy every $$$r\leq c$$$ is full-
0and full-1, which is either illegal or has $$$1$$$ connectivity.So actually row and column dictionary order and the connectivity have almost no connection. The only thing we need to ensure is the corner case of full-
1binary grid.thanks, that makes sense.
But what if $$$C=1$$$ and all rows are lexographically greater than all columns (and also $$$C=0$$$ in contrast)?
Is there a proof that such case cannot exist?
When 1st row and 1st column have both $$$0,1$$$, it's ok.
When 1st row and 1st column have only one character, we can cut down them.
Only treating 1st row has no $$$1$$$ is ok (other case can be treated in the same way).
1st row is $$$00\dots0$$$ and we have some $$$1$$$ in 1st column, so $$$r \lt c$$$ can be constructed.
some row is $$$1?\dots?$$$ and all column is $$$0?\dots?$$$, so $$$r \gt c$$$ can be constructed.
Edge case is a grid which have only $$$1$$$, but it's ok because then always $$$r=c$$$.
I wonder the sufficiency of such a construction: e.g. I can make 2 examples demonstrating the same logic:
101 010 101 which has both 0 and 1 in the 1st row and col and it's not connected.
110 110 000 which has both 0 and 1 in the 1st row and col and it's connected.
how is that connectivity decides whether there's such a configuration?
Connectivity is not matter. We can always find $$$r \lt c$$$ or $$$r \gt c$$$ unless the grid has all the same character.
Oh, I see your point. regardless of whether the graph is connected or not. we will have guaranteed that we can choose a row >= a col or a row < a col.
we just choose such a pair of row and col to deliver such a message denoting whether the graph is connected or not.
That is impossible.
Fact: If the grid has at least one 1 and one 0, then at least one row is (lexicographically) strictly larger than one column.
Proof: Let k be the number of leading 0's in the smallest column.
Case 1: If k = n, this case is trivial since at least one 1 exists in the grid.
Case 2: n > k >= 1.
If the numbers of leading zeros of all rows are greater than or equal k, than the first column contains all 0, violating k is the number of 0's in the smallest column.
Case 3: k = 0.
In this case, the first entry of all columns are 1 and the first row then contains all 1's, which is larger than the smallest row (since at least one 0 exists).
Rows and columns are symmetric. So we can also find a column strictly greater than a row.
I think I came up with the correct D2, but forgot to submit it imao. Might be one of my worst blunders ever.
for every i such that l<i<r and min(pl,pr)<pi<max(pl,pr) hold at the same time, you will set si to 1
Isnt this line so confusing, "for every i" part. the condition doesnt seem to hold true for every l<i<r (min(pl,pr)<pi<max(pl,pr)) in the arr. take this
5 3 4 2 1 5 01100
here non pass 5 1 5 1 4 5 5 4 5 4 5
the round except problem B is good
For B for me a big hint was that you needed to figure out if it was possible in less than 5 moves. If that 5 could be any number then you could binary search the answer and would get the minimum number of moves, yet the problem specifically said that you do not need to find the minimum number of moves so there was something special about the number 5...
5 is special because you can always do it in at most 5 moves, given that its possible ofcourse, and the figure 5 comes from that fact that u need at most 5 ranges to so.
For a string s where it is possible to do so,
the ends and the min/max permutation element would have their corresponding bit
in the string to be 'O'
so s if of the form 0 1 0 1 0 1 1 0 0 (min_index) 1 1 0 0 1 1 0 0 (max_index) 1 1 0 0
then we can always just pick the ranges
1 to min
1 to max
min to max
min to n
max to n
I know bro, I solved the problem...
I used another approach for C. So the idea came from that, for any path from (1, 1) to (2, n), we first go right, then down, then right again. So we can iterate each position i where we go down. And for fixed i, get the minimum value and maximum value on the path (1, 1) -> (1, i) -> (2, i) -> (2, n). This can be achieved by maintaining prefix min/max for the first row and suffix min/max for the second row.
Suppose for one path, the minimum value is L, maximun value is R. Then R, R + 1, ..., 2n is all legal for L. Also, R, R + 1, ... 2n is all legal for L — 1. So we can maintain the smallest R for every L when calculating each path. And after calculating L and R for every path, we can iterate L from 2n to 1, while maintaining the smallest R, and for every L, accumulate 2n — R + 1 to get the final answer. Here is my submission.348331154
Same idea but used segment tree with propagation on left sides to avoid duplicates.
I came up with the same idea.
But to get to the final count, After calculating L and R for each path,
I took the max L amongst all paths and minR amongst all paths and then the final count would be
maxL * (2 * n — minR + 1)
But idk why it fails?
348847633
UPD: Figured out what was wrong, taking maxL is wrong because, its possible that when we obtained a particular L value, it came from a path where the R value was > minR which means i would end up counting extra pairs for this particular L
Yes you are right. if you get the MinR from some (L, R) with a small L, then maybe you can't use this MinR for larger L.
Take this case for example.
5
3 3 3 2 2
10 10 10 3 9
Using your code, you would get MaxL = 3, MinR = 9. However you get MinR = 9 only when L = 2. So you can't use (3, 9).
Yep, thanks for sharing!
C.Monopati
Can you help me to find where my approach failed?
https://mirror.codeforces.com/contest/2163/submission/359292937
I track the min and max of each path and use the delta to calculate the change in each path to find the legal l&r.
Eventually reach Candidate Master after reaching Expert for over 500 days. Really really happy. Thanks for the great contest! ヾ(^∀^)ノ
loved the difficulty, luckily after 45 mins of thinking, I was able to solve B ^_^
Thank you to you all for making this round possible!
I think, the purpose of some Div2B problems is not to be solved.
i have a fun solution for E that is i think simpler than the one in the editorial: 348371787. though i was not yet able to prove its correctness. i have to prove that if all rows and all columns contain the same number of ones, then either the grid is disconnected or there are no zeros at all.upd: the solution is wrong. i apologize. here is a counterexample:
1 1 1 0
1 0 1 1
1 1 0 1
0 1 1 1
The good one that passes the tests, but fails on hacks :D
Before reading this I came up with something similar and I think an extension of this idea works.
Suppose that there aren't an equal number of ones in every row OR there aren't an equal number of one in every column. Then I claim we can always find a row with less ones than a column AND a column with less ones than a row; we can communicate C from this.
Remaining is the case where each row AND each column all have the same number of rows. Then either we have all ones, or there exists a zero => there exists at least one row starting with a zero, starting with one, column starting with zero, column starting with one; this is more than enough to communicate C.
The second player does the following: if all received entries are 1, C = 1. If the two vectors have different counts of 1, we are in the first case; otherwise we are in the second case.
Concise implementation here: 348401861
sob bro
guessed the solution for B in the last minute and it was correct
gg
whenever you get stuck on an easy question that requires an interesting point, come up with 10-20 different examples and try to solve it. you will automatically come up with the answer!!
Meanwhile, B,C were great! "C" 's implementation was beautiful :)
UDP: Now i realize i provided a different solution for C :) and it's in O(n)
adhocforces
Loved Problem A, also almost solved B, but was missing out on the indexes, overall loved the problems, although B was a bit difficult, got a lot to learn !
After seeing problem B felt like codechef, where questions are tangled around greedy ideas. I don't hate or like problem B but felt like thinking>>>coding.
fast editorial!
https://mirror.codeforces.com/contest/2163/submission/348377026 Problem C can someone explain why this fails ??
I tried merging the global left and right accordingly (does the order of the max and min, of the down right path affect this ?)
in problem B, min(p_l,p_r) is minimum over the range (l, r) or minimum of p_l and p_r ??
minimum of p_l and p_r
Can somebody kindly point out what I'm doing wrong here. Appreciate it. sub
you are doing if a[r]>m1: and if a[l]<m2: but it's the opposite
D1 also has a Nested binary search on answer solution which makes the number of queries = 2*log^2(n) 348380335
can some one explain why cant we use merge intervals approach to merge them ?
you are not merging them .
you are removing the ranges that are $$$\textbf{inside}$$$ another bigger range
so two ranges (1 , 5) and (4, 6) should both be added but if the second one was (2, 4) we can remove it .
Yeah we are only merging completely overlapping intervals
Problem C
This can be done by keeping two sets of de-activated cells, one for each row.Can somebody please explain what exactly is the author is doing in this line in the solution?
I appreciate the efforts you have done to create this contest however I noticed that adhoc became the reigning champion in the past 2 years. A div 2 should never be a speedforces (due to adhoc) contest. ABC should be accesible to pupils and D should be doable to specialists and experts.
I have seen some CMs and Ms failing at problem B/C in the recent few contests. This begs to question the process of reviewing the contests in the making.
Yea I was solving 3 problems last month. Can't even solve 2 now. It happened 3 times in a row at that
B -> another approach : we can replace cout << min(mn, mx) << " " << max(mn, mx)** with cout << 1 << " " << n**
No, we cant replace it. Think about the permutation 1 3 4 5 2 , if you replace min(mn,mx) and max(mn,mx) with 1 and n, that means we cant set any si to 1, cause max(p1,p5) is 2 and min(p1,p5)is 1.
this will be there so soln exist if 3,4 will have to be set to 1 and if u will try to get one at 1,5,2 then by any method u cant get soln
ok , you are right , this is a good idea.
B harder than C for the third time in a row. First the pinely round next the global round and now this. How come no one felt B was harder during testing.
My friend kafamcokkaristi wrote 348316517 a divide and conquer dp optimization for problem C, but we managed to create a case where it seems to take $$$O(N)$$$ distinct values, leading us to believe it runs in $$$O(N^2 \log N)$$$ in the worst case. However, from the
assert()statements we added, we observed that this value is actually $$$≤ 5$$$ in the tests. Still, since hacks are disabled in recent contests, we can’t submit a hack; could you please add it manually? SpyrosAliv Proof_by_QEDExample for $$$N=5$$$:
Done, thank you.
Interesting insight of problem D2. my D1 solution is based on binary search as well but D2 takes it to a new level. Loved the idea of Mex[l, r] = min(Mex[1, r], Mex[l, n])
Hi everyone, I tried solving this problem and my code seems to be failing on some test cases, but I’m not sure where the issue is. Could someone please take a look and let me know what I’m missing or doing incorrectly? Any guidance would be appreciated. Thank you! ~~~~~ //Your code here... void solve(){ int n; cin>>n;
vector<int>a(n),b(n); for(int i=0;i<n;i++)cin>>a[i]; for(int i=0;i<n;i++)cin>>b[i]; vector<int>mnleft(n),mxleft(n); vector<int>mnright(n),mxright(n); mnleft[0]=a[0]; mxleft[0]=a[0]; int maxi=0,mini=INT_MAX; for(int i=1;i<n;i++){ mnleft[i]=min(mnleft[i-1],a[i]); mxleft[i]=max(mxleft[i-1],a[i]); } mnright[n-1]=b[n-1]; mxright[n-1]=b[n-1]; for(int i=n-2;i>=0;i--){ mnright[i]=min(mnright[i+1],b[i]); mxright[i]=max(mxright[i+1],b[i]); } for(int i=0;i<n;i++){ maxi=max(maxi,min(mnleft[i],mnright[i])); mini=min(mini,max(mxright[i],mxleft[i])); } cout<<maxi*1ll*((2*n)-mini+1)<<endl;} ~~~~~
You are counting pairs that are not in solution.
For example, lets say n = 5 (2n = 10). And you got two mn, mx, one is [2, 6] and the other is [3, 7].
So all x <= 2 can make pair with y >= 6 and all x <= 3 can make pair with y >= 7.
But your code is taking x = max(2, 3) = 3 and y = min(6, 7) = 6. Your code counts the pair (3, 6) as a solution. But it is actually not a solution.
Focus on this fact and maybe you can solve the problem :)
that's valid point, i was mistaken. **** I made some changes here, although it failed-
I don't get why problem C is easier than problem B, man this shit ain't cool.
Is it possible to minimize the number of operations in B?
B was really hard to interpret...
Nice solution for E1 : Assume We want to check either m can be MEX or not what should I do ?
-> first we find the smallest right index where MEX(a[1]...a[right]) >=m . Similarly find the largest left index where MEX(a[left] .. a[right]) >=m . Now check either this range belongs to any given range or not. And yes this is the answer . Use nested binary search .
Total query 2*log(n)*log(n) Solution Link : https://mirror.codeforces.com/contest/2163/submission/348367619
Feels like the D2 idea is kinda being overlooked... The fact that the MEX of a segment equals the min of the MEX of two other segments seems useful (hopefully)
Yeah, it feels crazy to have never heard/thought of that. Very nice problem.
its alright if b was harder then expected. i really enjoyed the problem although i was not able to solve it.
Something's wrong with my solution for C and I can't find it. Could someone help? I've read and understand the editorial but part of me is curious as to what my solution misses.
For context, it uses a prefix mins and maxes on the top row and suffix mins and maxes on the bottom row to determine good boundaries and pushes them to a vector. The vector is then sorted and queried for the lower_bound for each i from 1 to 2n. The value 2n — endpoint + 1 is then accumulated and outputted.
I'm still trying to figure out what it is.
https://mirror.codeforces.com/contest/2163/submission/348351621
I have exact same problem and similar solution
Sorry if it's obvious, but for D1, how do we guarantee the number of queries is at most $$$300$$$? This is the single issue I haven't resolved with the same solution during the contest.
EDIT: My bad I misread the problem... See below. Thanks fugazi_zeitgeist.
Problem gives you at least 300 queries, not at most
It's weird. problem B that I find a correct solution quickly (by guessing), but even top-200 can't solve it.
It's too polarized?!!?
Though I even can't solve A and 0 problem in the end, when contest running :(
It seems that B is much harder than C
Problem B:
why taking the whole range wont give the answer? cause if s is 1 for min and max the answer would be no and for every other number the answer would be possible. ~~~~~ // this is code
string s;
cin>>s; f(i,0,n){ if(s[i]=='1'){ if(v[i]==1 || v[i]==n || i==0 || i==n-1){ cout<<-1<<endl; return; } } } cout<<1<<endl; cout<<1<<" "<<n<<endl;~~~~~
you misunderstood the satement as me. we cant take the whole range cause max(pl,pr) and min(pl,pr) doesnt hold for the whole range of [l,r] but only for the two numbers pl and pr.
Can anyone figure out that what's wrong in my approach for Problem B as I am getting wrong answer Contestant claims an answer does not exist, when it does exist. (test case 117):-
B's Description was misleading for me.Was solving some different problem for sometime.
Then, for every i such that l < i < r and min(p_l, p_r) < p_i < max(p_l, p_r) hold at the same time, you will set s_i to 1.
hold at the same time? Didn't tell what holds at the same time.
One direct way to interpret this is -> if this conditions holds for all i at the same time then set s[i] to 1.
Why my code wrong #8(problem C)? Who can tell me why, thanks.
N should be 4e5 /ll
Oh no,my rating QwQ
I solved (actually not) problem B and minimized the operations. Let i, j be the indices of the first and last units in x, then we can find mn1, mx1, mn2, mx2 in the range from 0 to i — 1 and from j + 1 to n — 1. Let's take the indices (mn1, mx2) and (mn2, mx1). After these operations, if s != x (if x[k] = 0, then we will not touch s[k]), then we output -1, otherwise these two operations. Unfortunately, I can't look at the tests, this solution gave WA 2 system test on test case 455. I really wonder why it doesn't work.
It doesnt work for the situation: 7 1 4 6 7 3 5 2 0010100
then you will use two intervals [1,6] and [2,7] but these two intervals cant let s3 became 1, cause your greatest chosen number if 5 , it is not greater than 6.
Doesn't [2, 7] cover all the necessary numbers? Except for another 7, which cannot be, tk p is a permutation
OK, I thought the first number was also part of the permutation, I'm sorry.
Thanks, this is a cool counterexample!
I was confused by the statement of B. I thought min(pl,pr) and max(pl,pr) holds for every pi which l<=i<=r ,and we just have to cout<<1<<" "<<n<<endl and all number except p1,p1,pmn,pmx could be counted.
Well.First, I need to thank the creator of this contest, because I have gained 172 ratings in this Div2.
But, I also need to say: What the f*** is Problem B?????
I think this sentence is bad: " $$$\min(p_l,p_r) \lt p_i \lt \max(p_l,p_r)$$$ "
It gave me -6 in B.
And I found it after CONTEST ENDING!!!!!
cheater
Could anyone tell me why my approach is wrong in question C https://mirror.codeforces.com/contest/2163/submission/348420021
It recounts a set of indices. For example, it's possible that for one index, valid set of indices are (1, 3), (1, 4), (1, 5) and then for next index, another valid set of indices are (1, 3), (1, 4), (2, 3), (2, 4). According to your code, it will take the maximum of the minimum as the left index (2 in this case) and minimum of the maximum as the right index (3 in this case) and then form all the combinations which also includes (2, 5) which is not there originally. I also made this mistake many times in this question
thanks
How is it possible that $$$(2, 3)$$$ is a valid combination but $$$(2, 5)$$$ is not?
If $$$(a, b)$$$ is valid then $$$(a - i, b + j)$$$ is valid for any $$$i, j$$$ such that $$$(a - i \ge 1) \land (b + j \le 2 * n)$$$. Isn't it true?
In other words, we have $$$a$$$ ways to choose the first index and $$$2 * n - b + 1$$$ ways to choose the second index. But solutions using this idea do not work for some reason.
UPD: I think I have found a counterexample:
If anyone's wondering why their solution fails, it might be insightful to test it against this test case.
Please help! What's wrong in my solution for D1? solution
Can someone please help me figure out what is the error in my code of problem C?
[problem:C]
[code] import java.util.*; public class Demo1 {
static void solve(Scanner sc){ int n=sc.nextInt(); int [][]arr=new int [2][n]; for(int i=0;i<2;i++){ for(int j=0;j<n;j++){ arr[i][j]=sc.nextInt(); } } int []mint=new int [n]; int []minb=new int [n]; int []maxt=new int [n]; int []maxb=new int [n]; int min=Integer.MAX_VALUE; int max=Integer.MIN_VALUE; for(int i=0;i<n;i++){ min=Math.min(arr[0][i],min); mint[i]=min; max=Math.max(max,arr[0][i]); maxt[i]=max; } min=Integer.MAX_VALUE; max=Integer.MIN_VALUE; for(int i=n-1;i>=0;i--){ min=Math.min(arr[1][i],min); minb[i]=min; max=Math.max(max,arr[1][i]); maxb[i]=max; } int temp=2*n; int []ans=new int [2*n+1]; int res=0; Arrays.fill(ans,Integer.MAX_VALUE); for(int i=0;i<n-1;i++){ int mini=Math.min(mint[i],minb[i]); int maxi=Math.max(maxt[i],maxb[i]); ans[mini]=Math.min(ans[mini],maxi); } int curr=Integer.MAX_VALUE; for(int i=(2*n);i>0;i--){ curr=Math.min(curr,ans[i]); if(curr!=Integer.MAX_VALUE){ res+=(temp-curr+1); } } System.out.println(res); } public static void main(String[] args) { Scanner sc=new Scanner(System.in); int t=sc.nextInt(); while(t-->0){ solve(sc); } }} [/code]
I have read the solution to Problem C and nifeshe's code, and found that our initial ideas were the same, but our approaches to solving the problem were quite different.Using my not-so-smart brain, I've summarized that my code is mainly based on the premise that the grid has only two rows. If the number of rows in the grid increases, the time complexity will grow exponentially. This is an area where I need to work hard to improve.But I still want to share my solution because I came up with it during the competition, even though there were some issues at the time that prevented it from passing. 348463330
I think Problem B is simple; the difficulty lies in understanding the problem statement and the proof. It's relatively easy to guess it's related to the fifth power.
Can someone help me? I don't know what's wrong with my solution for C. I have WA on 2nd test on 615th test case.
My submission:
minval[i] and minval[i+1] both have value. if minval[i+1] have optimal and minimum value then minval[i] = min(minval[i],minval[i+1]) , will correctly work
Oh thx, I see it now
It would be great if you could add hints and then solution.
Can someone tell what's the mistake in this code for Problem C? 348500673
Hello Codeforces team,
I want to confess that the coincidence in my solution for problem 2163C with user ekagra444/ happened because of my own actions.
During the contest, we were giving the round in a lab setup. I accessed a common system to view another participant’s code, which was a clear violation of the Codeforces rules. I completely understand that what I did was wrong.
I take full responsibility for this mistake and sincerely apologize for my actions. I assure that this will never happen again. I’ve learned from this experience and will strictly follow fair play rules in all future contests.
Please consider this as my honest confession.
Thank you for maintaining integrity in the platform.
can there be a solution for B such that we only use one operation. my solution is as follows but i cannot find what's wrong. we can take the range in which '1' extends and then find possible , l and r out of that range. ex :- 6 1 3 2 4 6 5 001100 // array is 1 — indexed
range in which '1'expands is (3, 4) so we search for min and max element in range (1, 2) && (5, 6).
as in this example "l" can be 1 and "r" can be "6";
funny thing is I thought I could do atmost 300 queries lol in $$$D1$$$ ,my solution does 210 queries at max there could be a medium version of this problem I think
same me first i had think then after working 3 hours and then again 1 hour i didn't read that but then my frnd told me that hey u can do n/2 think like that then i did logn queries for finding 0 and remove multiple queries have same l or r and what the final pairs i have i sort them based on the difference between them and just print in this order 1,n-1,2,n-2 ... upto n/2 — logn
Nested Binary Search on Answers solution of C. Time complexity is n(log2(n)^2)
348540251
is there a more rigorous proof for
After cleaning out those ranges, we are left with at most n ranges??I get the intuition that it's true but I couldn't make sure that that's actually the case.
My thinking is that
If we assume that there's no overlapping segment, then $$$|q|$$$ would be at most $$$n$$$ by having $$$[1,1],[2,2],[3,3],...,[n,n]$$$
If we assume that there's overlapping segment, then $$$|q|$$$ would be at most $$$n-1$$$ by having $$$[1,2],[2,3],...,[n-1,n]$$$.
But I still couldn't ensure my mind enough that clearing those segment will result in no-nesting $$$q$$$ with having $$$|q| \lt = n$$$
Each of the left end point is unique. And there can be at most $$$n$$$ left end points.
For problem B:
First,we begin by mapping each element $$$p_i$$$ to a point $$$(i,p_i)$$$ on the plane. The given operation is then equivalent to setting the value $$$s_i$$$ to 1 for every point $$$(i,p_i)$$$ that lies within a specified rectangle.
Second,though painting we can know there is only four useful points: $$$(1,p_1),(n,p_n),(mn,p_{mn}),(mx,p_{mx})$$$.Then you will find the solution immediately.
349532383
This is actually great intuition to solve B! I think the editorial should include this explanation instead of "Its natural to think".
O(n) solution for C ->353668810
I also tried with kinda similar approach. Can you explain the part from vector L onwards ?
D is amazing!
good for D
Can anybody explain the check function in problem C solution? Like is the straight line through first row or the second row not count? That is what it seems like to me..
D was amazing
Problem C can also be solved with binary search as you can loop through each number from 1 to 2N (letting the left bound be the current number) and greedily finding the lowest endpoint you can match it with since you know that every endpoint greater than that is sufficient as well.
Submission: 361215529
The Problem C is similar with this https://www.luogu.com.cn/problem/P15361?contestId=300994