Hope you enjoyed the round!
When all the elements of the array are equal, the solution is trivially impossible since the $$$\gcd$$$ of any subset will always be equal to $$$a_1$$$.
That is infact the only $$$\texttt{No}$$$ case. We show a construction otherwise.
Let $$$\operatorname{mx} = \max(a)$$$. Put all the elements equal to $$$\operatorname{mx}$$$ in one set, and all the other elements in the other set. Then, the $$$\gcd$$$ of the first set is $$$\operatorname{mx}$$$ while the other set will have a strictly smaller $$$\gcd$$$ (because $$$\gcd(a, b) \le \min(a, b)$$$)
Time complexity is $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while (t--){
int n; cin >> n;
vector <int> a(n);
for (int i = 0; i < n; i++){
cin >> a[i];
}
int mn = *min_element(a.begin(), a.end());
int mx = *max_element(a.begin(), a.end());
if (mn == mx){
cout << "No\n";
continue;
}
cout << "Yes\n";
for (int i = 0; i < n; i++){
cout << (1 + (a[i] == mx)) << " \n"[i + 1 == n];
}
}
return 0;
}
Suppose $$$\max(a) - \min(a) \le k$$$ holds, and there is at least one $$$a_i \ge 1$$$. Then, infact it is possible to take one apple while still keeping the condition of $$$\max(a) - \min(a) \le k$$$.
We will subtract from the maximum element. Then $$$\min(a)$$$ does not change except when $$$a_1 = a_2 = \ldots = a_n$$$. In that special case, you can check that the move is valid as $$$\max(a) - \min(a)$$$ becomes $$$1$$$.
In any other case, $$$\max(a)$$$ reduces by $$$0$$$ or $$$1$$$, so $$$\max(a) - min(a)$$$ only decreases, and thus $$$\max(a) - \min(a) \le k$$$ clearly holds.
Thus, for an array with $$$\max(a) - \min(a) \le k$$$, the only way for a player to lose is when all $$$a_i = 0$$$. But this happens exactly after the $$$\sum(a_i)$$$-th turn because each turn reduces $$$\sum(a_i)$$$ by $$$1$$$.
It may be possible that a first move itself is not possible. For example, in the case that $$$a = [4, 1], k = 1$$$. We should check that after subtracting the maximum element, the array has the property that $$$\max(a) - \min(a) \le k$$$ and immediately print $$$\texttt{Jerry}$$$ otherwise.
In the other case, we can simply print $$$\texttt{Tom}$$$ when $$$\sum(a_i)$$$ is odd, and $$$\texttt{Jerry}$$$ when $$$\sum(a_i)$$$ is even. This is because when $$$\sum (a_i)$$$ is odd, Tom will be the last person to make a move since he went first and the total number of turns is odd, and vice versa.
Time complexity is $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while (t--){
int n, k; cin >> n >> k;
vector <int> a(n);
for (auto &x : a) cin >> x;
long long sum = accumulate(a.begin(), a.end(), 0LL);
sort(a.begin(), a.end());
a[n - 1]--;
sort(a.begin(), a.end());
if (a[n - 1] - a[0] > k || sum % 2 == 0){
cout << "Jerry\n";
continue;
}
cout << "Tom\n";
}
return 0;
}
We assume that there is at least one $$$s_i = 0$$$ (unfilled position). In the other case that all $$$s_i = 1$$$, we can easily check if the maximum subarray sum is $$$k$$$ or not.
Let us first figure out when the answer is impossible. Replace all $$$a_i = -\texttt{INF}$$$ such that $$$s_i = 0$$$. If the maximum subarray sum is still $$$ \gt k$$$, then the answer is clearly impossible.
In every other case, the answer is infact possible! All positions with $$$s_i = 0$$$ will be kept $$$-\texttt{INF}$$$ except for $$$1$$$. Choose that position arbitrarily, let's call it $$$pos$$$.
Let $$$b =$$$ max prefix sum in the subarray $$$[a_{pos + 1}, a_{pos + 2}, \ldots, a_n]$$$. Let $$$c =$$$ max suffix sum in the subarray $$$[a_1, a_2, \ldots, a_{pos - 1}]$$$. Here we will allow the empty prefix and suffix too.
Suppose the value of $$$a_{pos} = x$$$. Then, the maximum subarray sum including $$$pos$$$ will be $$$x + b + c$$$.
And the maximum subarray not including $$$pos$$$ will be $$$\le k$$$, because thats equivalent to replacing $$$a_{pos}$$$ with $$$-\texttt{INF}$$$.
Thus, we can simply replace $$$x$$$ with $$$k - b - c$$$ and it will satisfy the conditions.
Let $$$f(x)$$$ be defined as the maximum subarray sum when we replace $$$a_{pos}$$$ with $$$x$$$.
Note the following properties of $$$f(x)$$$:
$$$f(-\texttt{INF}) \le k$$$: Because this is the assumption for the non-impossible case.
$$$f(k) \ge k$$$: Because the subarray $$$[a_{pos}]$$$ itself has a sum of $$$k$$$, so the maximum subarray sum must be greater.
$$$f(x + 1) \ge f(x)$$$ : Because increasing an element cannot reduce the maximum subarray sum.
$$$f(x + 1) \le f(x) + 1$$$: Because by increasing $$$a_{pos}$$$, each subarray increases by $$$0$$$ or $$$1$$$ depending on whether it includes $$$pos$$$. Thus, there is no way for the function calculating maximum subarray sum to increase by more than $$$1$$$.
With these observations, we can infact binary search on the first $$$x$$$ such that $$$f(x) = k$$$.
This is because, $$$f$$$ becomes continuous on the set of integers by the third and fourth property, and hence it will take all values in the range $$$[f(a), f(b)]$$$ for $$$a \le b$$$, and we have shown that $$$k \in [f(-\texttt{INF}), f(k)]$$$ by the first and second property.
In both solutions, be careful to avoid overflow. One simple way is to have $$$\texttt{INF} = 10^{13}$$$, as that is sufficient for our purposes (prevents overflow, but still larger than $$$k + \sum{a_i}$$$).
Time complexity: $$$O(n)$$$ or $$$O(n \cdot \log(A))$$$.
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while (t--){
int n;
long long k;
cin >> n >> k;
string s; cin >> s;
vector <long long> a(n);
for (auto &x : a) cin >> x;
int pos = -1;
for (int i = 0; i < n; i++){
if (s[i] == '0'){
pos = i;
a[i] = -1e13;
}
}
long long mx = 0;
long long curr = 0;
for (int i = 0; i < n; i++){
curr = max(curr + a[i], a[i]);
mx = max(mx, curr);
}
if (mx > k || (mx != k && pos == -1)){
cout << "No\n";
continue;
}
if (pos != -1){
mx = 0, curr = 0;
long long L, R;
for (int i = pos + 1; i < n; i++){
curr += a[i];
mx = max(mx, curr);
}
L = mx;
mx = 0;
curr = 0;
for (int i = pos - 1; i >= 0; i--){
curr += a[i];
mx = max(mx, curr);
}
R = mx;
a[pos] = k - L - R;
}
cout << "Yes\n";
for (int i = 0; i < n; i++){
cout << a[i] << " \n"[i + 1 == n];
}
}
return 0;
}
Note that the problem has a simple $$$O(n^2)$$$ solution by greedily finding the largest diameter in the current forest (set of disjoint trees) at every step, tiebreaking by the lexicographic order of the endpoints, then removing the diameter and continuing this process while at least $$$1$$$ node remains.
Property $$$1$$$: $$$2$$$ diameters always share at least one node.
With some background theory about diameters, this becomes trivial as when diameter length (in terms of nodes) is odd, they share a common central node; and when even, they share an edge (which shares $$$2$$$ nodes). Nevertheless, we provide an elementary proof.
Let $$$a_1, a_2, \ldots a_d$$$ and $$$b_1, b_2, \ldots b_d$$$ be $$$2$$$ distinct diameters that do not share any node.
Consider the closest pair of $$$2$$$ points in these $$$2$$$ paths, say $$$a_i$$$ and $$$b_j$$$ are closest. Then, the path $$$(a_i, b_j)$$$ cannot contain any other $$$a_k$$$ or any other $$$b_k$$$ because otherwise it would be a contradiction to the fact that they are closest.
Now, the length of the path $$$(a_1, b_1)$$$ is $$$(i - 1) + \operatorname{dist}(a_i, b_j) + (j - 1)$$$, where $$$\operatorname{dist}(x, y)$$$ denotes the number of nodes on the path $$$(x, y)$$$.
Assume that $$$i, j \ge \frac{d + 1}{2}$$$, then $$$\operatorname{dist}(a_1, b_1)$$$ is strictly larger than $$$d$$$ (using $$$\operatorname{dist}(a_i, b_j) \ge 2$$$), contradicting that $$$d$$$ is the diameter. In the other cases of $$$i, j$$$ being smaller than $$$\frac{d + 1}{2}$$$, we can check the pairs $$$(a_1, b_d), (a_d, b_1)$$$ and $$$(a_d, b_d)$$$. It is easy to see at least one of them will be larger than $$$d$$$.
Property $$$2$$$ : Let $$$(u, v)$$$ denote a diameter path, and $$$T$$$ denote the tree. Then $$$\operatorname{diam}(T \setminus (u, v)) \lt \operatorname{diam}(T)$$$ (strictly smaller).
This comes directly from the previous property. Since all diameters share at least one node, the new forest generated after removing path $$$(u, v)$$$ will have a strictly smaller diameter.
Property $$$3$$$ : In any sequence of positive numbers such that $$$a_1 + a_2 + \ldots + a_k \le n$$$ such that $$$a_i \lt a_j$$$ for all $$$1 \le i \lt j \le k$$$, $$$k$$$ is at most $$$O(\sqrt{n})$$$.
This is a classical property.
Note that $$$a_i \ge i$$$ for all $$$1 \le i \le k$$$ by induction. And thus, $$$a_1 + a_2 + \ldots + a_k \ge 1 + 2 + \ldots + k = \dfrac{k \cdot (k + 1)}{2}$$$.
But, $$$a_1 + a_2 + \ldots + a_k \le n$$$ implies $$$\dfrac{k \cdot (k + 1)}{2} \le n$$$, and so $$$k \le 2 \cdot \sqrt{n}$$$.
With these $$$3$$$ properties, we can now solve the problem. We describe the algorithm below:
Maintain a collection of subtrees (of nodes which have apples). Initially, the whole tree is there as one component.
For every subtree, find it's lexicographically largest triplet of $$$(d, u, v)$$$ using a BFS/DFS.
Remove the nodes on the diameter path for each subtree. This divides the component into several smaller subtrees. Add them to our collection.
Repeat steps $$$2$$$ and $$$3$$$ while our collection is non-empty.
Finally, sort (in descending order) the list of $$$(d, u, v)$$$ collected throughout all the steps, and output.
It is not hard to see that the above approach produces the correct answer. And it runs in $$$O(n \cdot \sqrt{n})$$$ time because steps $$$2$$$ and $$$3$$$ are repeated only $$$O(\sqrt{n})$$$ times.
Every smaller tree is formed from a larger "parent" tree. The diameter of the smaller tree is smaller than the diameter of the larger tree using Property $$$2$$$.
Suppose that there is some tree that is formed at $$$k$$$-th step. Then, consider the sequence of parent trees of this tree, and their diameters. Their diameters form a strictly increasing sequence, but their sum must be bounded by $$$n$$$ since we remove that many nodes, and total removed nodes is $$$n$$$. Thus, using Property $$$3$$$, we get $$$k \le \sqrt{2 \cdot n}$$$.
There are several correct ways to implement Step $$$2$$$. One of the neatest way is as follows: Find the furthest node from $$$1$$$, tie breaking lexicographically, say we got $$$x$$$. Find the furthest node from $$$x$$$, again tie breaking lexicopgraphically, say we got $$$y$$$. Then $$$(\max(x, y), \min(x, y))$$$ is the required diameter. To prove that these $$$2$$$ traversals are enough, you can use the fact mentioned in proof of property $$$1$$$, i.e. diameters share a central node or an edge (depending on parity). To find the furthest node, we can use BFS or DFS both fairly easily.
For step $$$3$$$, we can keep recursing to the parent of $$$y$$$ till we reach $$$x$$$, assuming we have calculated the parents of all vertices with a dfs from $$$x$$$. You may refer to the code.
#include <bits/stdc++.h>
using namespace std;
mt19937_64 RNG(chrono::steady_clock::now().time_since_epoch().count());
int main()
{
int t; cin >> t;
while (t--){
int n; cin >> n;
vector<vector<int>> adj(n + 1);
for (int i = 1; i < n; i++){
int u, v; cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector <bool> used(n + 1, false), seen(n + 1, false);
vector <array<int, 3>> ans;
vector <int> p(n + 1, -1);
while (true){
if (count(used.begin() + 1, used.end(), false) == 0){
break;
}
seen.assign(n + 1, false);
auto dfs = [&](auto self, int u, int par) -> pair<int, int>{
pair <int, int> ans = {1, u};
p[u] = par;
seen[u] = true;
for (int v : adj[u]){
if (v != par && !used[v]){
auto pi = self(self, v, u);
pi.first += 1;
ans = max(ans, pi);
}
}
return ans;
};
for (int i = 1; i <= n; i++) if (!used[i] && !seen[i]){
auto [d1, j] = dfs(dfs, i, -1);
auto [d2, k] = dfs(dfs, j, -1);
ans.push_back({d2, max(j, k), min(j, k)});
while (k != -1){
used[k] = true;
k = p[k];
}
}
}
sort(ans.begin(), ans.end(), greater<array<int, 3>>());
for (auto [x, y, z] : ans){
cout << x << " " << y << " " << z << " ";
}
cout << '\n';
}
return 0;
}
Solve the problem in $$$O(n \cdot \log(n))$$$.
Let $$$f_i,g_i$$$ be the longest and second longest path from $$$i$$$ in $$$i$$$'s subtree, the diameter will be $$$\max \limits_{i=1}^n {f_i+g_i}$$$.
When we find a diameter $$$(u,v)$$$, let update $$$f_u,g_u$$$ for all $$$u$$$ on the path $$$(\operatorname{lca}(u,v),\text{root})$$$. Note that the path $$$(\operatorname{lca}(u,v),\text{root})$$$ will be always shorter than the diameter, so the total update times will be $$$\mathcal O(n)$$$.
Use a std::set to find $$$f_u,g_u$$$ for every node $$$u$$$ and a std::priority_queue to maintain the maximum $$$f_i + g_i$$$, the total complexity is $$$\mathcal O(n \log n)$$$.
#include<bits/stdc++.h>
#ifdef DEBUG_LOCAL
#include <mydebug/debug.h>
#endif
using ll = long long;
const int N = 5e5+5;
using namespace std;
using pi = pair<int,int>;
using ti = tuple<int,int,int,int>;
int T,n,u,v,del[N],fa[N],ct; vector<int> g[N]; set<pi> t[N];
void dfs(int u,int f){
t[u].emplace(0,u),fa[u] = f;
for(int v : g[u]) if(v != f){
dfs(v,u); auto [x,y] = *--t[v].end();
t[u].emplace(x+1,y);
}
}ti gt(int u){
assert(t[u].size() >= 1);
if(t[u].size() == 1) return {0,u,u,u};
auto [x,y] = *--t[u].end();
auto [p,q] = *--(--t[u].end());
return {x + p,max(y,q),min(y,q),u};
}void los(){
cin >> n;
for(int i = 1;i <= n;i ++) g[i].clear(),del[i] = 0,t[i].clear();
for(int i = 1;i < n;i ++) cin >> u >> v,g[u].push_back(v),g[v].push_back(u);
ct = 0,dfs(1,0); priority_queue<ti> q;
for(int i = 1;i <= n;i ++) q.emplace(gt(i));
while(q.size()){
auto [di,u,v,d] = q.top(); q.pop();
if(del[d] || ti{di,u,v,d} != gt(d)) continue;
cout << di + 1 << " " << u << " " << v << " ";
while(u != d) del[u] = 1,u = fa[u];
while(v != d) del[v] = 1,v = fa[v];
del[d] = 1;
auto [x,y] = *--t[d].end();
while(fa[d] && !del[fa[d]]){
d = fa[d];
if(t[d].count({++x,y})) t[d].erase({x,y});
q.emplace(gt(d));
if(fa[d]){
auto [a,b] = *--t[d].end();
t[fa[d]].emplace(a+1,b);
}
}
}cout << "\n";
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(cin >> T;T --;) los();
}
Compute provably the exact worst case, and construct a tree that obtains it.
It can be proven that diameter decreases by $$$2$$$ each iteration and not just $$$1$$$, and it is possible to obtain this as we show later. So the best bound is $$$d$$$ where $$$1 + 3 + 5 + \ldots + (2 \cdot d - 1) \le n$$$, which comes out to be $$$\sqrt{n}$$$.
Let $$$L = \sqrt{n}$$$. Make $$$P_1, P_2, \ldots, P_L$$$ where $$$P_i$$$ is a line graph of size $$$2 \cdot i - 1$$$. Now, connect the central nodes of $$$P_i$$$ and $$$P_{i - 1}$$$ for all $$$i$$$. Refer to Wuhudsm comment for a picture.
Let $$$C(n, k)$$$ denote $$$\frac{n!}{k! \cdot (n - k)!}$$$.
We first start from the maximum possible value of $$$k$$$, and the tree that achieves it, i.e. a straight line path rooted at $$$1$$$. It is not too hard to see that this tree has the largest weight, and the weight of this tree is $$$C(n, 3)$$$. Thus, for $$$k \gt C(n, 3) + 1$$$, we answer $$$\texttt{No}$$$. We can prove the largest weight point by proving each node should have exactly $$$1$$$ child. Suppose instead some node $$$u$$$ has $$$\ge 2$$$ children, $$$c_1$$$ and $$$c_2$$$, but then if we attached $$$c_1$$$ to $$$c_2$$$ and broke the $$$c_1$$$ and $$$u$$$ edge, it increases the weight.
Now, infact the answer is possible for all $$$0 \le k \le C(n, 3) + 1$$$. We try to modify the line graph to give a valid construction. First of all, replace $$$k$$$ with $$$C(n, 3) - k$$$ and view the problem as reducing the weight of the line graph instead.
Suppose we broke the edge $$$(n - 1) - n$$$ and added the edge $$$x - n$$$, then the weight decreases by $$$C(n - x, 2)$$$. This is because the depth of LCA with nodes $$$n - 1$$$, $$$n - 2, \ldots, x$$$ change and they decrease by $$$n - x - 1, n - x - 2, \ldots 1$$$ respectively. Suppose, after this step, we further broke the edge $$$(n - 2) - (n - 1)$$$, and added the edge $$$y - (n - 1)$$$. It is tempting to say that the weight again decreases by $$$C(n - 1 - y, 2)$$$ but this is only true when $$$y \ge x$$$.
If we generalize the above, and break the edges $$$(i - 1) - i$$$ and add the edge $$$a_i - i$$$ ($$$a_i \lt i$$$), then the weight will decrease by $$$C(i - a_i, 2)$$$ as long as the sequence $$$a$$$ is decreasing (or $$$a_i = i - 1$$$, i.e. we do not change the parent). Because $$$a$$$ must be decreasing, that means that $$$i - a_i$$$ can only contain distinct elements (or $$$i - a_i = 1$$$).
This reduces the problem to Find sum of distinct elements of $$$C(i, 2)$$$ ($$$0 \le i \le n - 1$$$)at most $$$1$$$ from k.
Infact the greedy algorithm solves this problem, i.e. take the largest (untaken) value of $$$C(i, 2) \le k$$$ at each step.
We prove by induction. For $$$n \le 5$$$, it can be verified through bruteforce for all cases.
For $$$n \ge 6$$$, if $$$k$$$ is $$$\le C(n - 1, 3)$$$, just set $$$n = n - 1$$$ and by induction it is solvable. If $$$C(n - 1, 3) \lt k \le C(n, 3)$$$, then we set $$$k = k - C(n - 1, 2)$$$ and use induction. It can be verified that $$$0 \le k \le C(n - 1, 3)$$$ after this modification and so it is valid.
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while (t--){
int n; cin >> n;
long long k; cin >> k;
long long mx = 1LL * n * (n - 1) * (n - 2) / 6;
if (k > mx + 1){
cout << "No\n";
continue;
}
cout << "Yes\n";
k = mx - min(k, mx);
int p = n - 1;
for (int i = n; i >= 2; i--){
while (1LL * p * (p - 1) / 2 > k){
p--;
}
k -= 1LL * p * (p - 1) / 2;
cout << (i - p) << " " << i << "\n";
if (p != 1) p--;
}
}
return 0;
}
2107F1 - Cycling (Easy Version)
Let us try to figure out the optimal strategy. We want to use small values for the "overtake" operation, and we will use "swap" operations to make the overtakes less costly.
Suppose $$$p = $$$ first position of minima element. We should over take cyclists $$$1, 2, \ldots, p$$$ for the cost of $$$a_p$$$, swapping $$$p$$$ till first. This is because all $$$a_i (1 \le i \lt p)$$$ is $$$\ge a_p + 1$$$, and so the swap + overtake can't be worse. And obviously, if we are using $$$a_q (q \gt p)$$$, it is less costly in terms of swaps to use $$$p$$$ since the overtake cost cannot be worse.
Now, we might use the value $$$a_p$$$ for overtakes in the suffix as well, i.e. there exists some $$$q \ge p$$$ such that we overtake cyclists $$$1, 2, \ldots, q$$$ using $$$a_p$$$. This reduces the problem to the subproblem $$$a[q + 1, n]$$$, and thus we can use Dynamic Programming! But why are the problems independent in $$$a[q + 1, n]$$$ and the rest of the array? Suppose that we took some $$$a_i (i \le q)$$$ to be used for swaps in the suffix $$$a[q + 1, n]$$$, but we could then instead set up the swaps such that first $$$p$$$ reaches $$$q$$$, and then $$$p$$$ is taken for these suffix swaps. This won't add any additional swaps, and may only reduce the cost.
Let $$$dp_i$$$ be the answer for the suffix $$$a[i, n]$$$. Then, we compute $$$p = $$$ position of minima in $$$a[i, n]$$$, iterate on partition index $$$j$$$ such that we will take $$$p$$$ to $$$j$$$ using it for swaps $$$1, 2 \ldots, j$$$, value computed as $$$dp_{j + 1} + a_p \cdot (j - i) + S$$$, where $$$S$$$ denotes the total swaps made ($$$S = 2 \cdot (j - p) + (p - i - 1)$$$).
This solves the problem in $$$O(n^2)$$$.
#include <bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while (t--){
int n; cin >> n;
vector <int> a(n + 1);
for (int i = 1; i <= n; i++){
cin >> a[i];
}
vector <long long> dp(n + 1, 1e18);
dp[n] = 0;
for (int i = n - 1; i >= 0; i--){
int p = i + 1;
for (int j = i + 1; j <= n; j++) if (a[j] < a[p]){
p = j;
}
for (int j = p; j <= n; j++){
dp[i] = min(dp[i], dp[j] + 2 * (j - p) + 1LL * (j - i) * a[p] + (p - i - 1));
}
}
cout << dp[0] << "\n";
}
return 0;
}
2107F2 - Cycling (Hard Version)
Read the editorial for F1 first. We considered the positions that we would take $$$p$$$ to, which we assumed was $$$q$$$ and iterated $$$q = p, p + 1, \ldots, n$$$, finding the cost for each.
Property : Optimal $$$q$$$ is only $$$q = p$$$ or $$$q = n$$$.
Suppose $$$q \ne p$$$, i.e. we use $$$a_p$$$ for overtaking $$$p + 1$$$, and we used $$$a_i$$$ for overtaking $$$q + 1$$$. Then, if $$$a_p + 2 \le a_i$$$, it is not less optimal to overtake $$$q + 1$$$ using $$$a_p$$$ as well, and if $$$a_i \le a_p + 1$$$, it is not less optimal to overtake $$$q$$$ using $$$a_i$$$.
Thus, $$$q$$$ is only ever the "edges" of the ranges , i.e. $$$p$$$ or $$$n$$$.
Now, let $$$p_1$$$ be the first minima in $$$a[1, n]$$$, then $$$p_2$$$ be the first minima in $$$a[p_1 + 1, n]$$$, $$$p_3$$$ be the first minima in $$$a[p_2 + 1, n]$$$, and so on. Let $$$q_i = $$$ where $$$p_i$$$ is taken to for each $$$i$$$. Due to the above property, we can see that the optimal strategy is : for some $$$x$$$, $$$q_x = n$$$ and $$$q_i = p_i$$$ for $$$i \lt x$$$, i.e. choose to take some index $$$p_x$$$ to $$$n$$$, and the previous indices do not move.
We get a $$$O(n)$$$ solution for a single array by trying all values of $$$x$$$. But, we need to answer prefix queries.
Note that each option of $$$x$$$ gives a linear equation in the length of the array. And appending an element to the end of the array adds at most $$$1$$$ extra option for $$$x$$$. We can maintain all the linear equations in a CHT/Lichao tree and find the minimum each time.
It can be proven that only $$$min(a) \le a_i \le min(a) + 20$$$ need to be considered, and we will never overtake using a larger value. This property gives us simpler solutions in $$$O(n \cdot 20)$$$ with $$$0$$$ data structures.
Assume $$$min(a) = 1$$$. Let $$$L_i$$$ denote the number of overtakes using the value $$$i$$$, and we use values $$$1, 2 \ldots, k$$$. Then, it is easy to see the indices $$$1, 2, \ldots, L_1$$$ will be overtaken with $$$1$$$, after that $$$L_1 + 1, L_1 + 2, \ldots, L_2$$$ will be overtaken with $$$2$$$ and so on.
It should not be more optimal to take the value $$$i$$$ to cover the entire suffix, and so this gives us additional constraints of the form (by calculating the difference of costs in the current way, and the modified way) $$$2 \cdot (L_{i + 1} + L_{i + 2} + \ldots + L_k) \gt L_{i + 1} \cdot 1 + L_{i + 2} \cdot 2 + L_{i + 3} \cdot 3 + \ldots$$$. This simplies to $$$L_{i + 1} \ge L_{i + 3} + 2 \cdot L_{i + 4} + \ldots$$$.
Because of $$$L_{i + 1} \ge 2 \cdot L_{i + 4}$$$, we get a bound of $$$3 \cdot log_2(n)$$$, but the exact bound can be computed by a greedy approach.
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)1e18
#define inf 1e18
#define ld long double
mt19937_64 RNG(chrono::steady_clock::now().time_since_epoch().count());
struct chtDynamicMin {
struct line {
int m, b; ld x;
int om, ob;
int val; bool isQuery;
line(int _m = 0, int _b = 0, int _om = 0, int _ob = 0) {
m = _m;
b = _b;
om = _om;
ob = _ob;
val = 0;
x = -inf;
isQuery = false;
}
int eval(int x) const { return m * x + b; }
bool parallel(const line &l) const { return m == l.m; }
ld intersect(const line &l) const {
return parallel(l) ? inf : 1.0 * (l.b - b) / (m - l.m);
}
bool operator < (const line &l) const {
if(l.isQuery) return x < l.val;
else return m < l.m;
}
};
set<line> hull;
typedef set<line> :: iterator iter;
bool cPrev(iter it) { return it != hull.begin(); }
bool cNext(iter it) { return it != hull.end() && next(it) != hull.end(); }
bool bad(const line &l1, const line &l2, const line &l3) {
return l1.intersect(l3) <= l1.intersect(l2);
}
bool bad(iter it) {
return cPrev(it) && cNext(it) && bad(*prev(it), *it, *next(it));
}
iter update(iter it) {
if(!cPrev(it)) return it;
ld x = it -> intersect(*prev(it));
line tmp(*it); tmp.x = x;
it = hull.erase(it);
return hull.insert(it, tmp);
}
void addLine(int m, int b) {
int om = m, ob = b;
m *= -1;
b *= -1;
line l(m, b, om, ob);
iter it = hull.lower_bound(l);
if(it != hull.end() && l.parallel(*it)) {
if(it -> b < b) it = hull.erase(it);
else return;
}
it = hull.insert(it, l);
if(bad(it)) return (void) hull.erase(it);
while(cPrev(it) && bad(prev(it))) hull.erase(prev(it));
while(cNext(it) && bad(next(it))) hull.erase(next(it));
it = update(it);
if(cPrev(it)) update(prev(it));
if(cNext(it)) update(next(it));
}
int query(int x) const {
if(hull.empty()) return inf;
line q; q.val = x, q.isQuery = 1;
iter it = --hull.lower_bound(q);
return - it -> eval(x);
}
};
void Solve()
{
int n; cin >> n;
// insert lines and calculate CHT
chtDynamicMin cht;
vector <int> a(n + 1);
for (int i = 1; i <= n; i++){
cin >> a[i];
}
vector <int> pv(n + 1, 0);
// previous smaller
stack <pair<int, int>> st;
for (int i = n; i >= 1; i--){
while (!st.empty() && st.top().first >= a[i]){
pv[st.top().second] = i;
st.pop();
}
st.push({a[i], i});
}
vector <int> dp(n + 1, 0);
for (int i = 1; i <= n; i++){
dp[i] = dp[pv[i]] + a[i] * (i - pv[i]) + (i - pv[i] - 1);
// slope is +2 + a[i]
// constant - slope * i
int m = 2 + a[i];
int c = dp[i] - m * i;
cht.addLine(m, c);
int ans = cht.query(i);
cout << ans << " \n"[i == n];
}
}
int32_t main()
{
auto begin = std::chrono::high_resolution_clock::now();
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
cin >> t;
for(int i = 1; i <= t; i++)
{
//cout << "Case #" << i << ": ";
Solve();
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
cerr << "Time measured: " << elapsed.count() * 1e-9 << " seconds.\n";
return 0;
}








first.
Can some one help me what i did wrong in this submission, My Submission.
This is the submission for problem C, but I am getting out of bound error on string s, what have i missed?
Possible int overflow with
kcuzk ≤ 1e12. The error probably started there and ruined the rest.Thanks a lot, was stuck at this for a while. I was focusing on string overflow because error showed out of bound on string.
got same error wasted 25 mins in contest. and 400 points :(
In D, $$$\text{diam}(T \setminus (u,v)) \le 1/2 \text{diam}(T)$$$. This is because you are removing the center.
So if you recurse over subtrees after removing vertices, the complexity should be $$$O(n \log n)$$$.
Wrong. There are cases where its only a -2. We have tests which achieves the nsqrtn bound.
The "center" where all diameter passes is not the "center" in a normal $$$\mathcal O(n \log n)$$$ central decomposition.
Problem F1 can be solved greedily.
First, I reversed the array for simplicity.
Now, assume that the value in the first position is fixed. We can see that we can take this first element and swap it with the second one at a cost of $$$1$$$. Then, again, we can take the second element and swap it with the third one, also at a cost of $$$1$$$, and so on.
This is helpful because we can carry the smallest element seen so far and use it whenever we want, and the cost to use it is its value plus $$$1$$$.
So, at each position, we just have to choose whether to use its current value (which is
a[i], and then update the current minimum value toa[i], so it can be used in the next iteration), or simply use the minimum value carried all the way to this point plus $$$1$$$.To do this, we initially fixed the first element. But since $$$N \leq 5 \cdot 10^3$$$, we can simply iterate over all elements, assuming each one as the potential first element, solve the problem under that assumption, and then take the minimum among all of these.
Code: https://mirror.codeforces.com/contest/2107/submission/318519641
Thanks Joaozao for sharing the greedy approach. I tried similar greedy approach, but wasn't able to think that we only need one optimal index to start with. After seeing the comment it strike to me. Thank you!
learning a lot from D Tks:>
troll F1
Problem D is cool. This is my D solution
And this is my construction for bonus2:
The image does not load.
Your construction is intended, and can be proven to be optimal because diameter reduces by 2 wach step not just 1
good contest
I believe the time complexity in B should be $$$O(n$$$ $$$\cdot$$$ $$$log(n))$$$.
Good and educational contest!
The idea is $$$O(n)$$$, the given code runs in $$$O(n \log n)$$$ due to the call to sort, but that's not really necessary because you only need the maximum which you can find in $$$O(n)$$$ time.
Thanks so much! What's the background theory about diameters you mention for problem D exactly?
I find this blog very useful.
Thanks, this is very helpful! However, I meant something more along the lines of a general math theorem that describes how tree diameters behave. Is there some graph theory theorem for this? That's what their "common central node" remark led me to believe.
(Problem D)Can someone help me understand why my submission is TLE? I thought it is O(n) or O(nLogn). Idea is to calculate the largest diameter(while also making sure we pick the lexicographically largest nodes if tie), detach all the branches and compute the diameters of those branches too(recursively)
CODE : https://mirror.codeforces.com/contest/2107/submission/318555860
Why did I even bother with DP on trees in D...
How does your tree DP work for problem D?
Submission link: https://mirror.codeforces.com/contest/2107/submission/318526303
Let node 1 be the root of the tree. For every node we store the farthest child (if there is a tie, then the child with the maximum label) and the lexicographically greatest possible (d, u, v) in the subtree where the current node is the root. Then we begin traversing the tree from the root.
If current node is a part of the path (u, v), then it's sufficient to remove every node from u to v and process remaining subtrees, otherwise we process the subtree that contains the path (u, v), update every (not removed yet) ancestor of the root of the processed subtree and repeat the described algorithm in the current node again.
Apologies for the poor description, but this is probably the most horrible solution available for this problem and it's even more painful trying to explain it :)
Ok i get it
In the editorial of F1, I believe the transition should read $$$dp_{j + 1} + a_p \cdot (j - i + 1) + S$$$ instead of $$$dp_{j + 1} + a_p \cdot j + S$$$.
Thanks for nice problem set! Though scoring and order was IMO inadequate: F1 was much easier than D.
I don't agree the idea for D is easy its just the implementation that's a bit hard. For problem F1 I am sure that many people coded the greedy while having no proof why it works.
Also did you cheat on D? One of your submissions got skipped then immediately after that you submitted again. It looks like you changed variable names and submitted again but im not sure.
IMO, F1 is easier to realize than D. And for sure it's much easier to implement. I mean O(n^2) DP solution for F1, didn't even think about greedy once saw a constraint which made O(n^2) valid. About cheating dunno what do you mean. How one can cheat via resubmit? I've submitted AC solution for D 2 minutes before deadline, had no time to read F1 during contest, spent 1:40+ time on D :) After contest took some drink, read F1 and solved in less than 0:40. Good old school O(n^2) DP, not common at all these days :(
Yes but my point was if your submission got skipped that means that someone else wrote something very similar but it seems that you took that code that someone else had written down and changed couple things and resubmitted it
Please learn how to use codeforces before accusing someone.
You are correct that skipped might be because contest admins (like me) think its cheating. But there can be multiple other reasons: for example, if you accidentally take part in a contest you tested, we will skip your submissions. Or if you submit to the same problem multiple times after AC, your first submit will be skipped (there are non cheating reasons to do this)
This is a case of the last type
Probably that "someone else" was me. I've fixed what I though could be a bug and resubmitted a few seconds after previous submission. I saw AC for the previous submission, but at system testing it changed to "skipped".
in problem D. lets say the diameter of the tree is 19 from u to v and that would be (19,u,v). then there would exist a path of length 9 from x to y so (9,x,y). if i understand the solution correctly we pick the (19,u,v) first but isnt (9,x,y) lexicograpically the larger one? first stars with 1 and the second starts with 9.
array {19} is lexicographically larger than {9}. This isnt a string but an array of numbers so definition is based on the number and not the digits.
No thinking, raw CHT solution for F2.(everything 0 indexed)
same as the editorial, we start with dp[i] for i in 0..n, and we would like the make transition of the form: for some i<=k<j , we use element L[k] to cover the range i..j. -1. If v=L[i], the cost of this is v*(j-i) + (j-1-k) + (j-1-i). Unlike in the editorial, we do not reduce the number of transitions to consider away from n^3, but just do it.
thinking about this in another way, we are paying an additional cost of (v+1) for every element before L[k] and an additional(v+2) for every element after L[k].
We can imagine this as a 2-stage DP, where each element k pulls from before and push to after. Each of these can be handled with an add-only CHT (aka line container). Li Chao tree is also applicable here and is faster, but the constraints are pretty lenient. We need two different CHT/ Li Chao Tree, one for each component of the transition.
Complexity is n log n. You can check my submission for detailed calculations. (Idea took me 5 minutes but getting the formula right took me the remaining 20….)
Just adding a hopefully clearer write-up of this solution here.
Observation 1: We can partition $$$[1, n]$$$ into several maximal non-intersecting ranges such that for each range $$$[l, r]$$$ we use only element $$$a_y$$$ (where $$$l - 1 \leq y \leq r$$$), and no two ranges use the same element.
Exercise for the reader. It's easy to prove via contradiction.
Observation 2: The contribution of each such triple $$$[l, r, y]$$$ to the cost is $$$(r - y) + (a_y + 1) \cdot (r - l + 1) - 1$$$.
We swap $$$(y, r)$$$, then take $$$a_r$$$, swap $$$(r - 1, r)$$$, take $$$a_{r - 1}$$$, swap $$$(r - 2, r - 1)$$$...
We will use dynamic programming to find the optimal partition for each prefix.
Definitions:
Transitions (evaluated in increasing order of $$$i$$$):
Both transitions can be performed using two cht's.
The correctness of the first transition is fairly obvious, but what about that of the second? Notice that if use $$$y \lt r$$$ for some segment $$$[l, r]$$$, and we've already handled the cost on $$$[r, y]$$$ (which is done here through the term $$$\min(f(j, 0) + 1, f(j, 1))$$$), then the cost on $$$(y, l]$$$ is simply $$$a_y + 2$$$ per element ($$$1$$$ for the initial swap $$$(y, r)$$$, $$$1$$$ for the swap $$$(i, i + 1)$$$, and $$$a_y$$$ for simply taking that element). The exception here is the last element, which only has a cost of $$$a_y + 1$$$ as it doesn't require a $$$(i, i + 1)$$$ swap. So the total cost for $$$(y, r]$$$ is $$$(r - y) \cdot (a_y + 2) - 1$$$.
The answer for prefix $$$i$$$ is obviously $$$\min(f(i, 0), f(i, 1))$$$.
Code: 342809058
For question D, I initially thought of violence, but I didn't dare to write it because I didn't understand the complexity of the proof of greed. How can I improve the ability of greed
In the editorial for D, I'm not sure how property 3 is coming into play here. The property holds when all $$$a_i$$$ are distinct, but in this case, when we remove a diameter, the tree is split into a forest, and many components in that forest might have the same diameter (it would be smaller for sure, but repetition is possible). So we can't say that all $$$a_i$$$ are distinct right?
Edit: Understood now, we are looking from the perspective of each node, a single node won't be involved in more than $$$O(\sqrt(n))$$$ operations
Could explain how looking from the perspective of each node makes sure that there is
O(sqrt(n))subtrees?So in the end every single node will be disconnected right. Now for each node, let us focus only on operations which affected the component in which that node belongs. Since you're only focusing the operations performed in a particular component, the diameter will be strictly decreasing, hence as mentioned in the editorial, there can only be $$$O(\sqrt{n})$$$ operations that involve the connected component of that node, hence if we add this over all nodes, the total number of operations is $$$O(n \sqrt{n})$$$
Thank you for properly explaining time complexity in problem D, very helpful.
Problem D: Why is only the sum of diameters are considered to calculate the run-time? What about the run-time complexity of calculating the diameter itself for each component.. Where is the proof that calculating all the diameters for each component in the forest is also bounded by sqrt(n).
You find diameters in $$$\mathcal{O}(n)$$$ by DFS run
If we find diameters in O(n) for each component in the forest, how are we saying it is bounded by n sqrt(n)?
the point is that tree size reduces in each step, the proof in editorial explains that this reduction can't take more than sqrt N steps...
so yes you do O(n) to find the diameter but only sqrt N times.
Imagine like layers of merge sort... each layer altogether takes O(n) time but there are only logN layers.
Got it. Thank you so much!!
can anyone help me why i got wrong answer? 318519456
can someone please explain the DP solution for F1? Didn't quite understand from the editorial
I used this approach:
Let $$$d_i$$$ be equal to answer on prefix $$$[1,n]$$$. Base is $$$d_0 = 0$$$.
Now, we can move from $$$i$$$ to another index $$$j$$$ $$$(j \lt i)$$$ by using $$$a_i$$$, we always jump using $$$a_i$$$, so we move from $$$i$$$ to $$$i-1$$$ paying $$$a_i$$$, then we swaps $$$(a_i, a_{i-1})$$$ and so on, until we arrive at position $$$j$$$. Formula will look as $$$(j-i)\cdot a_i + j - i$$$ or something like that. Just iteratate over all possible $$$j$$$ in $$$\mathcal{O}(n)$$$.
And we can use another number $$$j$$$ $$$(j \lt i)$$$, swap $$$(a_i, a_j)$$$ and move from $$$i$$$ to $$$j$$$ using $$$a_j$$$ at each jump. Formula will look as $$$2(j-i)\cdot a_j + 2(j - i)$$$ or something like that. Just iteratate over all possible $$$j$$$ in $$$\mathcal{O}(n)$$$.
318653650 what's wrong with my submission,I use binarySearch find answer
Always think twice before setting -1 as an initial value in a problem that contains negative numbers.
get it! Thanks a lot,it takes my so much time
I didn't understand the proof of the greedy algorithm in problem E from the editorial. Can someone explain it?
Hello guys! I am solving problem D and could not get it
https://mirror.codeforces.com/contest/2107/submission/318765311 That is my solution for problem D, can anyone please explain why it is getting tl7?)
That is my solution — https://mirror.codeforces.com/contest/2107/submission/318799790
Upd: i did it)
I just want say the D is amazing!
for D problem, is the tutorial prove that the simple solution does not actually take O(n^2) but O(n.sqrt(n)) ? because I don't see the difference between the simple solution and the real solution
thanks to the authors for amazing tasks. Especially D and F1-F2 are amazing. The best round in 2025
Can someone explain how doing the two dfses is sufficient here? like what if we have 5 to 7 as a diameter and 6 to 8 as a diameter(and some others by the consequences of diameter) and the first dfs finds both 7 and 6 and chooses 7, if 7 to 8 is not a diameter, we will skip eight even though we should have picked it. What am I missing?
For problem D, the solution says that there is a $$$O(n^2)$$$ solution. That does mean one that is fast enough right? Because I though that $$$n \le 10^5$$$ was too big for that. Also, I believe this submission 318924590 is $$$O(n^2)$$$. Is $$$O(n^2)$$$ in fact just too slow or is my implementation not $$$O(n^2)$$$ or too inefficient?
In F,there is one wap at most,so you can count $$$(i,j)$$$(when going to $$$i$$$ out of $$$[i,n]$$$)and swap them and get a $$$O(n\log n)$$$ solution.
Here's submission
Yeah.I've solved hard F without tree,with only ST table. Link
O(nlogn) solution for D: (implementation details heavily rely on sets with a custom comparison struct)
let 1 be the root of the tree then for every path, there will be 1 node in it with the least depth (distance to 1)
we first traverse the entire graph by a dfs, the lexi-greatest path with node x as its root node (node with least depth), will be its 2 lexi-greatest branches, connected with itself.
we can obtain the lexi-greatest path of all nodes with a single dfs from 1 (O(n)) I also stored a childs set in each node, in lexi-order (O(nlogn) for all nodes)
insert all nodes in a set, that compares the lexi-value of the longest path of each node (O(nlogn))
then, remove the largest valued node in the set (this could be first or last depending on your ordering) remove all of the child nodes on this path) (O(klogn), k being the nodes removed)
notice, after removing these nodes, only the parents of the largest valued node would be impacted after the removal of these nodes, for nodes on other branches, the highest lexi-value path with them as the root node stays the same
and there are a maximum of k parent nodes, otherwise their would be a longer path than the removed one, so modifying these nodes also take O(klogn) time
here is my submission, my implementation skills on graph problems are **** but it shows the method works319444417
Thanks to this contest, I learned that apparently my dynamic convex hull trick implementation is wrong!
Good contest
Wasnt B too easy for a div 2 contest ??
could anyone tell me why my submission for D gets TLE on test 5, i do the same thing as mentioned in editorial. link to the submission
For the B problem, consider the case 2 boxes, k=1 and a1,a2=6,6. Tom plays first ->5,6. Jerry doesn't have any other option but to equalise or will lose due to the max-min<=k constraint-> 5,5. This continues and tom will end up winning. This is irrespective of summation of 'a' being even or odd. In this case summation is even and still tom wins. Please help where did i go wrong.
nvm, i thought who finishes the apples first in one box wins:'|
What if we have the max element more than one time, then we should compare with
max_element-min_element > k
Instead of max_element-min_element-1 > k
For e.g
4 2
7 7 4 5
Here Tom loses, but still winner according to solution?
Am I missing something?
In your example, after the first move (Tom chosing to reduce first occurence of 7 to 6) the array becomes a = [ 6, 7, 4, 5 ] after the move, d = max(a) = min(a) = 3, d > k follows --> Tom loses! According to the solution as well, Tom does lose.
In div2C, isn't it enough to limit INF to k=10^12? I'm not sure why we need to keep a_i terms in sum, as largest consecutive block will be at most 10^12 and summed with -INF, it will cancel out.
One simple way is to have INF=10^13 , as that is sufficient for our purposes (prevents overflow, but still larger than $$$k+\sum{a_i}$$$).