idea & solution: le0n
It can be observed that $$$s_n$$$ will not change throughout the operations, therefore, for the final string to have every character the same, every character must be equal to $$$s_n$$$.
To change every character to $$$s_n$$$, we can iterate over all characters from right to left, repeatedly setting $$$s_{i-1}\leftarrow s_i$$$ if $$$s_{i-1}\neq s_n$$$. Through this, we can need one operation for every character not equal to $$$s_n$$$, which is also obvious as a lower bound.
Time complexity: $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
char s[100005];
int main()
{
int n, t, i, m;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
scanf("%s", s + 1);
m = 0;
for(i = 1; i < n; i++)
m += (s[i] != s[n]);
printf("%d\n", m);
}
return 0;
}
idea & solution: le0n
The problem statement arised naturally from closing tabs in any modern browser.
After some experimenting, it can be seen that the answer does not exceed $$$2$$$. Simply click at $$$a$$$ as long as there's still a tab at that point. After that, each tab must have length of $$$b$$$, move the cursor to $$$b$$$, and click until all tabs have been closed.
Now it remains to be seen under what scenarios we can achieve $$$1$$$ move. Since the last tab closed will have length $$$b$$$, our cursor should be moved to $$$b$$$. Therefore, the answer will be $$$1$$$ when $$$nb\le a$$$, or $$$b=a$$$, and $$$2$$$ otherwise.
Remember to use long long if using multiplication to calculate $$$nb$$$.
Time Complexity: $$$O(1)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t, n, a, b;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &a, &b, &n);
printf(((long long)b * n <= a || b >= a) ? "1\n" : "2\n");
}
return 0;
}
idea & solution: le0n
We consider a simple strategy: repeatedly merge the smallest element onto the smaller of its two neighbours.
We will prove this greedy is correct: For any merge sequence, consider the smallest element $$$mn$$$, it must be merged into a larger element at some point in the future. However, its neighbour will not be smaller, which means that we can simply modify the merge sequence to merge $$$mn$$$ into its neighbours at the very first.
Further observation will show that this value is equal to $$$\sum_{i=1}^{n-1}\max(a_i,a_{i+1})+\max(a_n,a_1)-\max({a_1,a_2,\cdots,a_n})$$$. A brief sketch of the proof is as follows: It can be shown that we can break the ring into a sequence at an arbitrary maxima, since the maxima will not be merged into others.
For the problem on a sequence, consider each element $$$a_i$$$, find the closest element $$$a_x$$$ to the left of $$$a_i$$$, such that $$$a_x \gt a_i$$$ (when equal, break ties according to index). If there are elements between $$$a_x$$$ and $$$a_i$$$, then it's clear that in performing the aforementioned greedy, at some point we will merge everything in $$$a_{x+1},a_{x+2},\cdots,a_i$$$ into a single element, and then merge it into $$$a_i$$$. Therefore the answer will be increased by $$$a_i$$$ if $$$a_{i-1} \lt a_i$$$. The same thing will happen to the right of $$$a_i$$$. Therefore the answer is $$$\sum_{i=1}^{n-1}[a_i\ge a_{i+1}]a_i+[a_i \lt a_{i+1}]a_{i+1}$$$, which can be rephrased as $$$\sum_{i=1}^{n-1}\max(a_i,a_{i+1})$$$, which in turn is the formula above.
However, this is not needed to pass the problem. We expected participants to pass using doubly linked lists, sets, or any other data structures which can support the operations needed.
Time Complexity: $$$O(n)$$$ or $$$O(n\log n)$$$.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
ll a[N];
int main()
{
int t, n, m, i;
ll k;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
m = 0;
for(i = 0; i < n; i++)
{
scanf("%lld", a + i);
if(a[i] > a[m])
m = i;
}
a[n] = a[0];
k = -a[m];
for(i = 0; i < n; i++)
k += max(a[i], a[i + 1]);
printf("%lld\n", k);
}
return 0;
}
// In the name of Allah.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
list<int> alive;
int a[n];
list<int>::iterator w[n];
auto c_next = [&alive](const list<int>::iterator& it) {
return next(it) == alive.end() ? alive.begin() : next(it);
};
auto c_prev = [&alive](const list<int>::iterator& it) {
return it == alive.begin() ? --alive.end() : prev(it);
};
auto hole = [&](const list<int>::iterator& it) {
return a[*it] <= min(a[*c_next(it)], a[*c_prev(it)]);
};
for (int i = 0; i < n; ++i) {
cin >> a[i];
w[i] = alive.insert(alive.end(), i);
}
queue<int> q;
{
int i = 0;
for (auto it = alive.begin(); it != alive.end(); ++it, ++i)
if (hole(it))
q.push(i);
}
long long ans = 0;
bool mark[n] = {};
while (alive.size() > 1) {
auto i = q.front();
q.pop();
if (mark[i])
continue;
mark[i] = true;
auto it = w[i];
ans += min(a[*c_next(it)], a[*c_prev(it)]);
auto jt = c_next(it);
alive.erase(it);
it = jt;
if (hole(it))
q.push(*it);
it = c_prev(it);
if (hole(it))
q.push(*it);
}
cout << ans << '\n';
}
}
idea & solution: Flamire
For a multiset $$$S$$$, we will find a check to determine whether it can be generated.
For each color $$$x$$$ not in $$$S$$$, we need to somehow "hide" all of the $$$x$$$'s in other sets. That is, for every partitioned set, the occurrence of $$$x$$$ must be less than or equal to the occurrence of the modes.
For each color $$$c$$$ in $$$S$$$, no matter how many times $$$c$$$ appeared in $$$S$$$, or how we partition these $$$c$$$ into different sets, the color $$$c$$$ can provide at most $$$cnt_c$$$ "chances" to hide an element of $$$x$$$.
Therefore, $$$cnt_x\le\sum_{c\in S}cnt_c$$$ must hold.
It is easy to construct a partition once this condition is held for all $$$x$$$. Thus, we only need to count sets that satisfy $$$\max_{x\not\in S} cnt_x\le\sum_{c\in S} cnt_c$$$.
This is a simple knapsack dp problem from here, you can either add elements in increasing order of $$$cnt$$$ and keep track if the last color is used at all, or observe that the condition is just $$$\sum_{c\in S}cnt_c\ge\max cnt$$$, and just running a completely vanilla knapsack dp.
Time Complexity: $$$O(n^2)$$$.
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5, P = 998244353;
int n;
int a[N], cnt[N];
int dp[N];
void solve() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
memset(cnt, 0, sizeof cnt);
int max_cnt = 0;
for (int i = 1; i <= n; ++i) {
max_cnt = max(max_cnt, ++cnt[a[i]]);
}
memset(dp, 0, sizeof dp), dp[0] = 1;
for (int i = 1; i <= n; ++i) if (cnt[i]) {
for (int j = n; j >= cnt[i]; --j) {
dp[j] = (dp[j] + 1ll * cnt[i] * dp[j - cnt[i]]) % P;
}
}
int ans = 0;
for (int i = max_cnt; i <= n; ++i) (ans += dp[i]) %= P;
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
idea & solution: le0n
Some participants mentioned that similar ideas have appeared recently. We knew of at least one such problem, however, the problem was already proposed and accepted at that time.
I believe that the problems are not identical, though similar ideas were used, it is also a show of skill to remember and reuse ideas learnt from previous problems. Therefore, I would like to think the problem does have a place in the contest.
There was an oversight on the preparation of this problem, the tests did not include enough small tests, which allowed some codes with wrong implementation to pass. We apologize for the inconvenience.
There are many ways to approach this problem, my personal approach is as follows:
Consider what kind of $$$a$$$ would satisfy the requirements, after some exploring, we can arrive at the following check: Sum each bit of $$$a$$$, resulting in an integer sequence, if this sequence is lexicographically larger or equal to the binary representation of $$$c$$$, then $$$a$$$ is ok.
This can be explained by considering bits from high to low:
- If at some point we have more $$$a$$$'s than $$$c$$$, we can use a 1-bit on this position to fix everything under this bit.
- If at some point we have $$$0$$$ a's and the $$$c$$$ bit is $$$1$$$, it's then obvious that we cannot satisfy the conditions, since we also cannot use higher bits to change the situation, as this will cause higher bits to be less than $$$c$$$.
Thus, we have obtained a clean check to $$$a$$$.
To minimize the $$$+1$$$ operations, we will iterate bits from high to low, if the current $$$a$$$'s is less than $$$c$$$, we will have to select a single $$$a$$$ element, and increase it to the point that the current bit is $$$1$$$. Note that we will not increase two $$$a$$$ elements, since in reaching the state, we will inevitably reach the state where one of the $$$a$$$ is $$$1000\cdots00$$$, and the other one is $$$0111\cdots11$$$, this is already enough.
From here, observe that only the maximum $$$O(\log V)$$$ elements are used, we can easily achieve a complexity of $$$O(n\log n+q\log^2V)$$$, or $$$O(n\log n+q\log V\log\log V)$$$ with heaps.
#include <bits/stdc++.h>
#define N 500011
#define ll long long
using namespace std;
int T,n,q,a[N];
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)scanf("%d",a+i);
sort(a+1,a+1+n,greater<int>());
int nn=min(n,32);
while(q--)
{
int c;scanf("%d",&c);
static int b[44];ll ans=0;
for(int i=1;i<=nn;++i)b[i]=a[i];
for(int i=29;~i;--i)
{
int cc=0;
for(int j=1;j<=nn;++j)cc+=b[j]>>i&1;
if(cc>(c>>i&1))break;
if(cc<(c>>i&1))
{
int id=1;
for(int j=2;j<=nn;++j)if(b[j]>b[id])id=j;
ans+=(1<<i)-b[id];
b[id]=0;
}
else for(int j=1;j<=nn;++j)b[j]&=~(1<<i);
}
printf("%lld\n",ans);
}
}
}
idea & solution: le0n
Some participants mentioned that similar ideas have appeared recently, we did not know of this.
This problem was initially proposed with a Hall-dp solution, also with complexity $$$O(n)$$$, but testers told us of a simpler greedy solution.
Reduce the problem to bipartite matching.
Devise a greedy algorithm to solve the matching problem, and prove it (or not).
The problem can be formulated as a minimum path cover, which in turn can be converted into a bipartite matching problem:
- For each element in $$$a$$$, create both a left side vertex and a right side vertex, each left side vertex with value $$$a_i$$$ can match right side vertices with index larger than $$$i$$$, and with value $$$a_i-1$$$ or $$$a_i+1$$$.
It can be observed that the graph can be partitioned into two unconnected components by parity.
A certain intuition the matching for $$$a_i=1$$$ stricter than $$$a_i=3$$$, maybe we can try just letting the $$$a_i=1$$$ greedily choose the next element, and just believe that it will work out.
Therefore, we can propose a greedy algorithm: we iterate values $$$v$$$ from small to large, for every vertex with value $$$v$$$ on the left side, if it is unmatched, we match it with a $$$v+1$$$ on the right side with index closest to it, we do the same for value $$$v$$$ vertices on the right side.
We can prove that this is correct: Consider an element with $$$a_i=1$$$, if it did not match the closest $$$a_i=2$$$ on the right, we will try to substitute this pair into the final matching.
Suppose our $$$a_i=1$$$ vertex is $$$A$$$, the $$$a_i=2$$$ vertex on the right is $$$B$$$. If we insert $$$A-B$$$ into the matching, and discard any preexisting matches with $$$A$$$ or $$$B$$$, the only case where we our matching size decreases is when $$$A$$$ and $$$B$$$ are both matched with some $$$C$$$ and $$$D$$$, respectively.
It can then be shown by simple reasoning that $$$C$$$ and $$$D$$$ can be matched, which means our matching size will not be reduced.
Therefore, we can choose any $$$a_i=1$$$ and the closest $$$a_i=2$$$, and simply delete them from the graph.
Thus, the greedy is proved.
Implementation should be easy. Time Complexity: $$$O(n\log n)$$$ or $$$O(n)$$$.
Observation: construct a bipartite graph with $$$2n$$$ vertices, named $$$L_1,L_2,\dots,L_n$$$ and $$$R_1,R_2,\dots,R_n$$$. There is an edge between $$$L_i$$$ and $$$R_j$$$ iff $$$i \lt j$$$ and $$$|a_i-a_j|=1$$$. The answer to the original problem is $$$n$$$ minus the size of the maximum matching of this graph.
Consider using hall theorem on $$$L_1,L_2,\dots,L_n$$$, thus we only need to calculate $$$\max |S|-|N(S)|$$$.
Separate $$$L$$$ into $$$L_{odd}$$$ and $$$L_{even}$$$, which contains all the $$$L_i$$$ with odd $$$a_i$$$ and vice versa. Let $$$S_{odd}=S\cap L_{odd}$$$ and $$$S_{even}=S\cap L_{even}$$$ we can see that $$$|S|-|N(S)|=|S_{odd}|-|N(S_{odd})|+|S_{even}|-|N(S_{even})|$$$, so we can calculate the two parts separately.
For $$$\max |S_{odd}|-|N(S_{odd})|$$$, if adding an element to $$$S_{odd}$$$ doesn't make $$$N(S_{odd})$$$ bigger, we can always add it. So we only need to consider $$$S_{odd}$$$ that for every odd value $$$x$$$, all the elements in $$$S_{odd}$$$ with value $$$x$$$ forms a suffix of all appearances of $$$x$$$ in array $$$a$$$.
We can define $$$dp_{i,j}$$$ as the maximum $$$|S_{odd}|-|N(S_{odd})|$$$ when only considering elements with value $$$\leq i$$$ in $$$S_{odd}$$$ and $$$N(S_{odd})$$$ (where $$$i$$$ is always odd), and the elements with value $$$i$$$ forms the suffix starting from position $$$j$$$. Since $$$\sum cnt$$$ is bounded by $$$O(n)$$$, we have a total of $$$O(n)$$$ states. The dp transitions between $$$i$$$ and $$$i+2$$$ can be done easily in linear time, so the total complexity is $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
bool vis[N];
int a[N], n;
vector<int> pos[N * 2];
int solve()
{
int i, p, ans = 0;
vector<int> tmp;
for(i = 1; i < 2 * n; i++)
{
if(i & 1)
{
p = 0;
for(auto o: pos[i])
{
while(p < pos[i + 1].size() && pos[i + 1][p] < o)
p++;
if(p < pos[i + 1].size())
vis[pos[i + 1][p++]] = 1;
}
}
else
{
p = pos[i + 1].size();
reverse(pos[i].begin(), pos[i].end());
for(auto o: pos[i])
{
while(p && pos[i + 1][p - 1] > o)
p--;
if(p)
vis[pos[i + 1][--p]] = 1;
}
}
tmp.clear();
for(auto o: pos[i + 1])
if(vis[o])
ans++;
else
tmp.emplace_back(o);
pos[i + 1] = tmp;
}
return ans;
}
int main()
{
int t, i, ans;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", a + i);
for(i = 1; i <= n; i++)
vis[i] = 0;
for(i = 1; i <= 2 * n; i++)
pos[i].clear();
for(i = 1; i <= n; i++)
pos[a[i]].emplace_back(i);
ans = n - solve();
reverse(a + 1, a + n + 1);
for(i = 1; i <= n; i++)
vis[i] = 0;
for(i = 1; i <= 2 * n; i++)
pos[i].clear();
for(i = 1; i <= n; i++)
pos[a[i]].emplace_back(i);
ans -= solve();
printf("%d\n", ans);
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5, inf = 1e9;
int a[N], lp[N], rp[N], Lp[N], m;
vector<int> pos[N * 2], dp[N * 2], tmp;
int solve()
{
int i, j, u, v, p;
dp[1].resize(pos[1].size());
for(i = 0; i < pos[1].size(); i++)
dp[1][i] = i;
for(i = 1; i < m; i += 2)
{
u = pos[i].size() - 1;
v = pos[i + 2].size() - 1;
tmp.clear();
tmp.resize(u + 1);
dp[i + 2].clear();
dp[i + 2].resize(v + 1);
for(j = 0; j <= u; j++)
tmp[j] = dp[i][j] - rp[pos[i][j]];
for(j = u; j > 0; j--)
tmp[j - 1] = max(tmp[j - 1], tmp[j]);
for(j = 0; j <= v; j++)
{
p = pos[i + 2][j];
if(j)
dp[i + 2][j] = dp[i + 2][j - 1];
if(Lp[p] < u)
dp[i + 2][j] = max(dp[i + 2][j], j + tmp[Lp[p] + 1]);
dp[i + 2][j] = max(dp[i + 2][j], j - lp[p] + dp[i][Lp[p]]);
}
}
return dp[m].back();
}
int main()
{
int t, n, i, ans;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
m = 0;
ans = n;
for(i = 1; i <= n; i++)
{
scanf("%d", a + i);
m = max(m, a[i]);
ans -= 2 * (a[i] & 1);
}
m |= 1;
for(i = 1; i <= m; i++)
pos[i] = {0};
for(i = 1; i <= n; i++)
{
pos[a[i]].emplace_back(i);
lp[i] = (a[i] > 1 ? pos[a[i] - 1].size() - 1 : 0);
rp[i] = (a[i] < m ? pos[a[i] + 1].size() - 1 : 0);
Lp[i] = (a[i] > 2 ? pos[a[i] - 2].size() - 1 : 0);
}
ans += solve();
reverse(a + 1, a + n + 1);
for(i = 1; i <= m; i++)
pos[i] = {0};
for(i = 1; i <= n; i++)
{
pos[a[i]].emplace_back(i);
lp[i] = (a[i] > 1 ? pos[a[i] - 1].size() - 1 : 0);
rp[i] = (a[i] < m ? pos[a[i] + 1].size() - 1 : 0);
Lp[i] = (a[i] > 2 ? pos[a[i] - 2].size() - 1 : 0);
}
ans += solve();
printf("%d\n", ans);
}
return 0;
}
idea & solution: Flamire
Our testers had vastly different opinions on the difficulty on this problems, some were able to solve within 20mins, and others failed to solve within a sufficiently long time. We eventually decided to put it at E, and it seems to have did its work.
The answer is increasing, try solve for the maximum number of colors for a certain inconvenience $$$d$$$.
Every color is a connected component.
There exists a diameter-midpoint like structure.
The optimal answer has a certain structure, try finding it.
We switch the answer and the parameter, and solve for the maximum number of colors for a given diameter $$$d$$$.
A simple intuition is that each color should be a connected component, this is also easily provable: If some color is not connected, we can choose one of its "outermost" components (a more rigorous definition would be the leaves of the auxiliary tree of its components), and change it to the color of its adjacent component. In doing this, the number of different components is decreased, and our inconvenience has not increased. Therefore, after enough changes, each color will be a connected component.
The problem asks for a diameter-like value, therefore, we can try to find a diameter-midpoint-like structure:
- When $$$d$$$ is odd, there exists a color component such that the distance to all other vertices does not exceed $$$\frac{d-1}2$$$.
- When $$$d$$$ is even, there exists a vertex such that the distance to all other vertices does not exceed $$$\frac d2$$$.
Now, observe that we can "push" colors away from the midpoint and out to the leaves, to increase the number of color used, our optimal solution would look something like this:

Therefore, the optimal solution is:
- For odd $$$d$$$, remove the outermost $$$(d-1)/2$$$ levels of leaves.
- For even $$$d$$$, remove the outermost $$$d/2-1$$$ levels of leaves, and choose a maximum degree vertex in the remaining tree.
Time Complexity: $$$O(n\log n)$$$ or $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
vector<int> e[N];
int val[N], cnt[N], deg[N], h[N], d;
queue<int> q;
int del(int x)
{
cnt[deg[x]]--;
cnt[--deg[x]]++;
return deg[x];
}
int main()
{
int t, n, i, u, v, k, c;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(i = 1; i <= n; i++)
e[i].clear();
for(i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
e[u].emplace_back(v);
e[v].emplace_back(u);
}
for(i = 0; i <= n; i++)
{
val[i] = 1e9;
cnt[i] = 0;
h[i] = 1;
}
for(i = 1; i <= n; i++)
cnt[deg[i] = e[i].size()]++;
for(i = 1; i <= n; i++)
if(deg[i] == 1)
q.push(i);
c = 0;
d = n;
while(!cnt[d])
d--;
val[1] = min(val[1], 1);
val[d] = min(val[d], 2);
while(!q.empty())
{
k = q.front();
q.pop();
for(auto o: e[k])
if(del(o) == 1)
{
h[o] = h[k] + 1;
q.push(o);
}
++c;
while(!cnt[d])
d--;
val[c + 1] = min(val[c + 1], 2 * h[k] + 1);
val[c + d] = min(val[c + d], 2 * h[k] + 2);
}
for(i = n - 1; i >= 1; i--)
val[i] = min(val[i], val[i + 1]);
for(i = 1; i < n; i++)
printf("%d ", val[i]);
printf("\n");
}
return 0;
}
idea & solution: Flamire
No, we did not propose a paper problem. We knew of the paper on permutation pattern matching in advance, but we assumed the paper would not help much in solving the problem, either due to coding complexity, or constants hidden by the notation that would make it impractical. I'll admit that I did not read the paper in full (procrastination), but from what I gathered, it seemed that understanding the paper would be harder than solving the problem in itself.
If I am mistaken, please let me know.
We only need to calculate the minimum $$$r$$$ for each $$$l$$$, try breaking $$$21435$$$ into smaller parts.
When we fix the $$$21$$$-part, we need to append a $$$435$$$-part such that $$$val_3 \gt val_2$$$, and $$$index_4 \gt index_1$$$. (Here the footnotes refer to the value order, rather than index order.)
Therefore, we need to find $$$435$$$-subsequences that are Left-Right-Min minimal, that is, there does not exist another $$$435$$$-subsequence that is better in all three aspects.
The number of such $$$435$$$-subsequences is small. Try analyzing what kind of subsequence are minimal.
Perform scanline on the value of "$$$3$$$" from large to small, at most one $$$435$$$ will be added each time.
It suffices to find the minimal $$$r$$$ such that $$$[l,r]$$$ contains a $$$21435$$$-avoiding subsequence for every $$$l$$$.
We will refer to the elements by value order, instead of index order, in the following text, i.e. "$$$2$$$"-element refers to the leftmost element, with the second smallest value.
When we have fixed $$$l$$$, the "$$$2$$$"-element will be fixed, the "$$$1$$$"-element will just be the next element that is smaller than it, therefore, we only need to append a $$$435$$$-subsequence to it.
As we need to minimize $$$r$$$, and $$$val_3 \gt val_2,index_4 \gt index_1$$$ should be satisfied, we will need to consider all Left-Right-Min minimal $$$435$$$'s, that is, the ones where there does not exist another $$$435$$$ that is better in all three aspects.
To analyze this, we can try performing scanline on the $$$val_3$$$ from large to small, we can perform some substitutions to reduce the number of $$$435$$$'s we need to consider.
Through this, we can find a surprisingly strong restriction on minimal $$$435$$$'s: For each $$$i$$$ being considered as the "$$$3$$$"-element, the "$$$5$$$"-element must be $$$nxt(i)$$$, the closest element to the right of $$$i$$$, with value greater than $$$a_i$$$.
We perform substitutions as follows:

The three cases corresponds to:
- Left: $$$val_5 \lt val_{nxt(i)}$$$, by definition, $$$index_5 \gt index_{nxt(i)}$$$, substitute "$$$5$$$" by $$$nxt(i)$$$.
- Middle: $$$val_5 \gt val_{nxt(i)},val_4 \lt val_{nxt(i)}$$$, substitute "$$$5$$$" by $$$nxt(i)$$$.
- Right: $$$val_5 \gt val_{nxt(i)},val_4 \gt val_{nxt(i)}$$$, substitute $$$i$$$ by $$$nxt(i)$$$.
When "$$$3$$$" and "$$$5$$$" are fixed, "$$$4$$$" is also fixed. Therefore, there are at most $$$n$$$ minimal $$$435$$$'s, and they can be found by simple data structure techniques.
After finding the minimal $$$435$$$'s, the problem can be reduced to simple 2D-queries.
Time Complexity: $$$O(n\log n)$$$.
#include <bits/stdc++.h>
#define N 1000011
using namespace std;
int T,n,a[N],id[N];
int R[N];
struct sgt
{
int D,mx[N*4];
int query(int l,int r)
{
l+=D-1;r+=D+1;int ans=0;
while(l^r^1)
{
if(!(l&1))ans=max(ans,mx[l^1]);
if(r&1)ans=max(ans,mx[r^1]);
l>>=1;r>>=1;
}
return ans;
}
void modi(int k,int p)
{
k+=D;mx[k]=p;
while(k>>=1)mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
void clear()
{
D=1;while(D<=n+10)D<<=1;
for(int i=0;i<D+D;++i)mx[i]=0;
}
}T1,T2;
int pl[N],res[N],curr[N];
int Rmn[N];
void proc()
{
for(int i=1;i<=n;++i)R[i]=Rmn[i]=i+1,id[a[i]]=i,pl[i]=0;
for(int i=n;i;--i)while(R[i]<=n&&a[R[i]]<a[i])R[i]=R[R[i]];
for(int i=n;i;--i)while(Rmn[i]<=n&&a[Rmn[i]]>a[i])Rmn[i]=Rmn[Rmn[i]];
T1.clear();
for(int i=1;i<=n;++i)
{
if(R[i]<=n)
{
int k=T1.query(a[i]+1,a[R[i]]-1);
pl[i]=k;
}
T1.modi(a[i],i);
}
T2.clear();
for(int i=1;i<=n;++i)curr[i]=res[i]=0;
for(int i=n;i;--i)
{
int x=id[i],y=Rmn[x];
if(y<=n)
{
int rr=n+1-T2.query(y+1,n);
if(rr<=n)res[rr]=max(res[rr],x);
}
if(pl[x])T2.modi(pl[x],curr[pl[x]]=max(curr[pl[x]],n+1-R[x]));
}
for(int i=1;i<=n;++i)res[i]=max(res[i],res[i-1]);
}
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",a+i);
proc();
long long ans=0;
for(int i=1;i<=n;++i)ans+=res[i];
printf("%lld\n",ans);
}
}








first.
By the way, I was sure that there was some sort of pattern in the problem names, but I could not figure it out. Maybe there is, if there is I just don't see it. But I do think that the name of C. Binary Wine does not fit in with the other names.
First of all, all of the names except for Binary Wine and Arctic Acquisition afaik stand for common competitive programming things when said forward or in reverse.
Same Difference = Data Structures
Tab Closing = Time Complexity
Cyclic Merging = Candidate Master
Marble Council = ^
Binary Wine = ???
Path Split = Shortest Path
Rainbow Branch = Regular Bracket (sequence)
Arctic Acquisition = Alcoholics Anonymous..?
So from here it looks like Arctic Acquisition and Binary Wine don't belong. However, we can insert the common beginning vowel in Arctic Acquisition into the middle of the acronyms of the other titles (and possibly reverse the result to get these):
SAD, CAT, CAM, MAC, SAP, BAR
but then for Binary Wine neither BAW or WAB is a word.
D2C/D1A,
But the solution didn't use doubly linked list.

Another day of linked list being forgotten.
I think D2E is easier than D2D,it's solution more natually. And I used doubly linked lists in D2C,it's obviously harder to code.The official solution is better
harder to code but coming up with that fancy logic is tougher than implementing a double linked list if you have some practice before of DLL.
Maybe. I didn't think to much and write the DLL.But without doubt,it has much details.
top 3 reasons for depression
breakup
Substance Abuse
WA in div2 A
I am in support of you bro
FR
what is Hall-dp solution in Div1 — D ? Flamire
Added.
Guys, i think there is error in solution to problem B(Closing tabs). Why there can't answer be greater than 2? Take a look at test case 6, i think for this, we will have to move the cursor 6 times. Kindly take a look at it.
We can prove that the only positions that we need to click are the end position a and the max size of tab b.
yeah , i hope someone could provide a mathmatical proof on why it couldnt be greater than 2 ;
Suppose there are initially x tabs, each with width n / x. Your mouse is currently on the close button of the last tab.
After closing one tab, the number of tabs becomes x − 1, and each tab gets new width n / (x − 1).
Now consider two cases:
Case 1: n / (x − 1) > b
tab's size is b now !
⟹ you must move the mouse to the new location of the first tab’s close button.
Case 2: n / (x − 1) ≤ b
Then tab's size will be n / (x − 1)
Your previous cursor position was at the right edge of the last tab:
old_pos = (n / x) * x (we have x tab with n/x len)
new_pos = (n / (x-1)) * (x — 1) (we have x-1 tab with n/(x-1) len)
So the close button ends up exactly at the same position as before. ⟹ No need to move the mouse.
there are 2 exclsuive situations and they spends of 2/1 moves, therefore we are guaranteed to have the problem solved in at most 2 moves: 1. the total length of tabs greater than window size e.g:
then you'll have to move the cursor to the right most tab and close tabs until it reachs situation 2.
hope that gives you some intuition
If you think so
You may even try on chrome tabs itself !!
It's always <= 2 for sure !!
My soln :: https://codeforces.me/contest/2166/submission/359960116
Shouldn't the last line of the tutorial of Div2D/1B be
max cnt <= \sum_{i \in S} cnt_i?could you add abit more context to hall-dp mentioned in problem D's editorial ?
Could you link the editorial to the contest?
I'm a bit disappointed with the editorial, especially after waiting for 24 hours.
For 2165A — Cyclic Merging, it would have been interesting to see:
rather than the straightforward implementation of the formula, which doesn't bring any added value.
I think an explanation could be the following: consider a graph of $$$n$$$ edges of weight $$$w_i = \max(a_i, a_{(i+1)\bmod n}),$$$ connecting vertices $$$a_i$$$ and $$$a_{(i+1)\bmod n}$$$. You want to build a minimum spanning tree over it. Using Kruskal's algorithm, you pick $$$n-1$$$ edges: all except one having weight $$$\max_i w_i$$$. Therefore, the total weight is $$${\sum_{i=1}^n w_i} - \max_i w_i$$$.
You could think that this problem is not equivalent to the original one, because after picking an edge $$$(a_i, a_{i+1})$$$ (aka merging $$$a_i$$$ and $$$a_{i+1}$$$), $$$w_{i-1}$$$ or $$$w_{i+1}$$$ might increase to $$$w_i$$$, if $$$w_i \gt w_{i-1}$$$ or $$$w_i \gt w_{i+1}$$$, but Kruskal picks edges ordered by weight, so this is not possible (i.e. you are guaranteed that $$$w_{i-1} \ge w_{i}$$$ or that $$$w_{i-1}$$$ was already picked, same for $$$w_{i+1}$$$, therefore at every step the weights remain unchanged).
I feel there’s a nicer explanation, but I'm unable to find it; if you have one, I’d really appreciate if you could share it.
Thanks for your feedback, I have added my proof of the formula, which I hope will be understandable. I have also sourced a greedy implementation from the testers, please check it out.
Here's how I did div2C. I started off with the same idea as the editorial, greedily merge the two adjacent elements with the smallest max. However, I couldn't think of a nice way to implement this, so I tried to make some more observations.
Assume we have a set which stores the max of every pair of adjacent elements, and observe how it changes after we merge the elements with the smallest max.
Let these elements be $$$a,b$$$, WLOG $$$a \leq b$$$. Let the element adjacent to $$$a$$$ (and is not $$$b$$$) be $$$x$$$, and let the element adjacent to $$$b$$$ similarly be $$$y$$$. If we merge $$$(a,b)$$$ to $$$b$$$, the only max of our set which could change is $$$\max(x,a)$$$ to $$$\max(x,b)$$$. But since $$$b$$$ was the smallest max, $$$max(x,a) \geq max(a,b)$$$. Taking cases whether $$$a = b$$$ or not, we get either $$$a = b$$$ or $$$x \geq b$$$, and in both cases the element of our set doesn't change.
So our answer is just the $$$n-1$$$ smallest elements of the original set. The largest element of the set is just the max of the array, so just subtract that from the sum of the set. This solves it in $$$O(n)$$$, and doesn't really involve any extra knowledge like cartesian trees.
Thanks for this, it is a very nice way of proving their mathematical formula, you helped me solve it :)
Comment canceled because of downvotes.
In the div2C instead of checking for smallest element, what if we check for the neighbours of max element. Those can only pair with the other guy (not the maximum). So answer should be the sum of max of all pairs to the left of max cyclically. But could anyone proof that this is always true? For me it passed all the test cases...
I had misinterpreted DIV1 — D as we can also rearrange the elements within subsequence. In other words, we have to partition elements into subsets and each subset's elements can be rearranged in a sequence and they satisfy the required property. Is this version solvable ?
amazing
Why did you provide such a hard tutorial to the D1D (Hall-dp) when it's just greedy?
Any reason why undervoting me?
P. S. When I wrote this comment there was no "disclaimer" saying anything about greedy.
Can you provide some good resources about minimum path cover and how to translate it to bipartite matching? The Wikipedia article is not very illuminating.
Ok I've spent a while looking into this now, and idk how helpful it will be but here's the way I understand it.
A path cover is just any set of (directed) edges, such that each vertex has at most one incoming and one outgoing edge in the set.*
The minimal path cover corresponds to the set with the most edges, since the number of paths in that cover is $$$V-E$$$.
If we create two copies of the vertices, one copy on the 'left' and one on the 'right,' then we'll start drawing edges between them, and let's say that an (undirected) edge from left to right represents outgoing from the vertex represented on the left and incoming into the one on the right. What's cool is that our constraint "at most one incoming and one outgoing per vertex" now translates into "at most one (undirected) edge per vertex in this new copy graph." One vertex copy represents the incoming edge and the other represents the outgoing one. And this is EXACTLY the condition of a bipartite matching.
So if we build a bipartite matching on the new graph (which in this round's problem the graph is created implicitly), it represents a path cover (at most one incoming and outgoing edge per vertex in the original graph), with the same number of edges (we sort of just 'glue' the left and right halves back together or superimpose them or whatever)! And if we build the MAXIMAL bipartite matching, then this will be the minimum path cover (since it has the most edges).
The solution for 2165D in the editorial does this matching in two passes, first finding the outgoing edges from odd vertices to even ones (effectively only odd on the left and even on the right, basically ignoring all implicit evens on the left half), then finding all the outgoing edges from evens on the left incoming into odds on the right. These two matchings can be composed using simple addition since the Even->Odd graphs and Odd->Even graphs don't interfere with each other.
* I think this reframing of the problem was the key to me finally getting that Eureka moment
Can someone pls explain Div2D? How to approach writing DP for it? The solution does not seem to be very intuitive.
Any intuition/thought process behind it will be much appreciated
@Flamir please explain your DIV2D , knapsack DP more.
Can someone explain where and why this is failing ....
Simpler solution for Div1A/Div2C
Main thing is the maximum element will be selected in last so we can put it in front then we dont need to think about the array being cyclic then merge adjacent elements greedily
tuff iota abuse in c 381187850