Thanks for participating in Codeforces Round 1122 (Div. 3)!
How many participants can possibly have solved all three problems?
At most $$$\min(a_1,a_2,a_3)$$$ participants could have solved all three problems. This is achievable by making the same $$$\min(a_1,a_2,a_3)$$$ participants solve every problem, then distributing the remaining solves arbitrarily.
Thus, the answer is $$$n-\min(a_1,a_2,a_3)$$$.
The complexity is $$$O(1)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N; cin >> N;
int a, b, c; cin >> a >> b >> c;
int m = min({a,b,c});
cout << N-m << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}
Consider the cases $$$a\geq b$$$ and $$$a \lt b$$$ separately.
If Alice ever takes stones, she should take all of them.
If $$$a\geq b$$$, Alice takes all $$$c$$$ stones immediately. There is nothing left for Bob to use to reduce her lead, so the score is $$$a+c-b$$$.
Now suppose $$$a \lt b$$$. Alice can take $$$0$$$ stones, and Bob will also take $$$0$$$ because he is already ahead and taking more stones would only increase the score. This gives $$$b-a$$$. Otherwise, Alice should take all $$$c$$$ stones at once. Taking only part of them gives a difference between the two cases of taking none and taking all, so it cannot be better than both. Taking all gives $$$|a+c-b|$$$.
If $$$a+c \lt b$$$, this is smaller than $$$b-a$$$. Otherwise, it equals $$$a+c-b$$$. Therefore, the answer is $$$\max(|a-b|,a+c-b)$$$.
The complexity is $$$O(1)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int a, b, c; cin >> a >> b >> c;
cout << max(abs(a-b),(a+c-b)) << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}
If a prefix contains both $$$0$$$ and $$$1$$$, what are its bitwise AND and bitwise OR?
A sorted binary string is determined by one split point.
If a prefix contains both $$$0$$$ and $$$1$$$, its AND is $$$0$$$ and its OR is $$$1$$$, so its last character can be changed to either value.
If $$$s_1=1$$$, the first character can never change, so the final string must be all ones. Every zero can be changed using OR, giving the number of zeros as the answer.
Now suppose $$$s_1=0$$$. Fix the point after which the ones start. For a split after $$$i$$$, we need to change every one in $$$[1,i]$$$ and every zero in $$$[i+1,n]$$$. We can first change the required zeros on the right using OR, then change the required ones on the left using AND. A split inside the initial block of zeros is never better than moving it to the end of that block.
So, scan every split while maintaining the number of ones on the left and zeros on the right, and take the minimum.
The complexity is $$$O(n)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N; cin >> N;
string s; cin >> s;
int z = 0;
int o = 0;
for (int i = 0; i < N; i++) {z+=(s[i]=='0');}
if (s[0]=='1') {cout << z << endl; return;}
int aa = 1e9;
for (int i = 0; i < N; i++) {
o+=(s[i]=='1');
z-=(s[i]=='0');
aa=min(aa,o+z);
}
cout << aa << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}
Look at how the height and position of each section change after an operation.
A section moving one position to the right gains $$$1$$$ height, while a section moving one position to the left loses $$$1$$$ height.
During an operation, every section passed over moves one position to the right and gains $$$1$$$ height. The section being moved goes $$$j-i$$$ positions to the left and loses exactly $$$j-i$$$ height. Thus, for every section, $$$\text{height}-\text{position}$$$ never changes. The section initially at position $$$i$$$ therefore always keeps the value $$$a_i-i$$$.
We can also reorder the sections however we want by building the desired order from left to right and repeatedly moving the required section into the next position.
Suppose $$$k$$$ consecutive positions starting at $$$p$$$ are flat at height $$$h$$$. Their invariant values are $$$h-p,h-p-1,\ldots,h-p-k+1$$$, which are $$$k$$$ distinct consecutive integers. The reverse is also true: if $$$k$$$ sections have consecutive values $$$a_i-i$$$, placing them in decreasing order makes their heights equal.
Therefore, the answer is the longest consecutive run among the distinct values $$$a_i-i$$$. Put them in a set and scan in increasing order.
The complexity is $$$O(n\log n)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N; cin >> N;
set<int> s;
for (int i = 1; i <= N; i++) {
int a; cin >> a;
s.insert(a-i);
}
int aa = 0;
int tt = 0;
int c = -1e9;
for (auto x : s) {
if (x!=c+1) {aa=max(aa,tt); tt=0;}
tt++;
c=x;
}
aa=max(aa,tt);
cout << aa << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}
Use DP. Let $$$dp_i$$$ be the minimum number of operations needed to turn one $$$i$$$ into elements which are all at most $$$k$$$.
Let $$$dp_i$$$ be the minimum number of operations needed to turn one $$$i$$$ into elements which are all at most $$$k$$$. Clearly, $$$dp_i=0$$$ for $$$i\leq k$$$.
For $$$i \gt k$$$, suppose we choose a prime divisor $$$p$$$ of $$$i$$$. One operation gives us $$$p$$$ copies of $$$i/p$$$, and these copies can then be handled independently. Thus, $$$dp_i=\min_{p\mid i,\ p\text{ prime}}(1+p\cdot dp_{i/p})$$$.
Since $$$i/p \lt i$$$, compute the DP in increasing order. We can precompute the distinct prime divisors of every number with a sieve. Finally, the original elements are independent, so the answer is $$$\sum dp_{a_i}$$$.
The complexity is $$$O(n\log\log n)$$$ per test case after preprocessing.
Can you solve the problem for all $$$f(1),f(2),\ldots,f(n)$$$?
This was actually the original version of the problem!
#include <bits/stdc++.h>
using namespace std;
vector<long long> pf[200001];
long long dp[200001];
bool cmp[200001];
void pre() {
for (long long i = 2; i <= 200000; i++) {
if (!cmp[i]) {
cmp[i]=true;
for (long long j = 2*i; j <= 200000; j+=i) {
pf[j].push_back(i);
cmp[j]=true;
}
pf[i].push_back(i);
}
}
}
void solve() {
long long N, K; cin >> N >> K;
long long aa = 0;
vector<long long> dp(N+1,1e18);
for (long long i = 1; i <= N; i++) {
if (i<=K) {dp[i]=0;}
for (auto x : pf[i]) {dp[i]=min(dp[i],dp[i/x]*x+1);}
}
for (long long i = 0; i < N; i++) {
long long a; cin >> a;
aa+=dp[a];
}
cout << aa << endl;
}
int main() {
pre();
long long T; cin >> T;
while (T--) {solve();}
}
Work backwards from one copy of the value you want to create.
Process the values from large to small, and let $$$q$$$ be the number of copies of the current value that you need.
If you need $$$q$$$ copies of $$$x$$$ but only have $$$c \lt q$$$, the missing $$$q-c$$$ copies of $$$x$$$ each force another copy of every smaller value.
We check whether a value $$$M$$$ can appear, then binary search the largest valid $$$M$$$. The largest initial value is already present, so only larger values need to be checked.
Work backwards from one copy of $$$M$$$. At first we need one copy of every value below it, so set $$$q=1$$$ and process the values downwards. Suppose we currently need $$$q$$$ copies of $$$x \gt 0$$$, and there are $$$c$$$ copies of $$$x$$$ in the initial multiset. If $$$c\geq q$$$, we use $$$q$$$ of them and have $$$c-q$$$ extras. If $$$c \lt q$$$, the missing $$$q-c$$$ copies of $$$x$$$ each require another copy of every smaller value. Thus, $$$q$$$ becomes $$$q+(q-c)=2q-c$$$.
So the transition is $$$q\leftarrow q+\max(0,q-c)$$$. Extra positive elements cannot save us at another positive level, but they can all be turned into zeros by taking them alone. We count these extras, and when we reach $$$0$$$, the check succeeds exactly when the initial zeros plus all extras are at least $$$q$$$.
Missing values are easy to skip. If there are $$$d$$$ missing values in a row, then $$$q$$$ doubles $$$d$$$ times, so multiply it by $$$2^d$$$ at once. We can also cap $$$q$$$ once it becomes larger than the total number of elements to avoid overflow.
If $$$M$$$ is possible, then every smaller value is also possible, since all of them have to exist while building $$$M$$$. Therefore, binary search works. After sorting the pairs, one check is $$$O(n)$$$.
The complexity is $$$O(n\log n+n\log C)$$$ per test case, where $$$C$$$ is the binary search range.
Can you get a much smaller upper bound for the binary search?
Let $$$mx=\max x_i$$$.
You only need to search up to about $$$mx+50$$$. Once we go much further than $$$mx$$$, there are many consecutive missing values, and every missing value doubles $$$q$$$, so the required number of elements grows too quickly.
Thus, we can binary search only on $$$[mx,mx+50]$$$, giving $$$O(n\log 50)$$$ checks after sorting.
The exact proof and bound are left to the reader :)
#include <bits/stdc++.h>
using namespace std;
bool check(long long mid, vector<pair<long long, long long>> &A) {
long long n = 1;
long long ex = 0;
long long p = mid;
for (long long i = 0; i < A.size(); i++) {
if (p-A[i].first+(63-__builtin_clzll(n))>60) {return false;}
n<<=(p-A[i].first-1);
if (!A[i].first) {ex+=A[i].second; break;}
if (A[i].second>n) {ex+=A[i].second-n;}
else {n=(n<<1)-A[i].second;}
p=A[i].first;
}
return (ex>=n);
}
void solve() {
long long N; cin >> N;
vector<pair<long long, long long>> A;
long long lo = 0;
long long hi = 1000000100;
for (long long i = 0; i < N; i++) {
long long a, b; cin >> a >> b;
A.push_back({a,b});
lo=max(lo,a);
}
sort(A.rbegin(),A.rend());
if (A.back().first) {A.push_back({0,0});}
while (lo<hi) {
long long mid = (lo+hi+1)/2;
if (check(mid,A)) {lo=mid;}
else {hi=mid-1;}
}
cout << lo << endl;
}
int main() {
long long T; cin >> T;
while (T--) {solve();}
}
Process the tree from the leaves upward.
A node can always be brought back to its original value after changing it.
For every node $$$i$$$, its reachable values have the form $$$(a_i+g_ix)\bmod b_i$$$ for some integer $$$x$$$. Find $$$g_i$$$.
For every node $$$u$$$, let $$$g_u$$$ be such that its reachable values are exactly $$$(a_u+g_ux)\bmod b_u$$$. We compute $$$g_u$$$ from the leaves upward.
Suppose $$$v$$$ is a child of $$$u$$$. If $$$g_v=b_v$$$, then $$$v$$$ is fixed at $$$a_v$$$. Otherwise, its value can change from $$$a_v$$$ by multiples of $$$g_v$$$. Let $$$S_u$$$ be the sum of the initial values of all direct children of $$$u$$$. We can add $$$S_u$$$ to $$$u$$$ by leaving all children at their initial values, and every non-fixed child $$$v$$$ lets us vary this amount by multiples of $$$g_v$$$. Therefore, $$$g_u=\gcd(b_u,S_u,g_v\text{ for all non-fixed children }v)$$$.
For a leaf, this gives $$$g_u=b_u$$$, as expected. Once we know $$$g_u$$$, the largest reachable value is $$$a_u+\left\lfloor\frac{b_u-1-a_u}{g_u}\right\rfloor g_u$$$.
These maxima can all be achieved together. We can first set a node to its maximum, then continue working strictly inside its children's subtrees without changing that node. So after computing all $$$g_u$$$ bottom-up, we simply sum the maximum reachable value of every node.
The complexity is $$$O(n\log 10^9)$$$ per test case.
#include <bits/stdc++.h>
using namespace std;
void dfs(long long node, long long par, vector<long long> &A, vector<long long> &B, vector<long long> &g, vector<vector<long long>> &adj) {
long long gc = 0;
long long tt = 0;
for (auto x : adj[node]) {
if (x != par) {
dfs(x,node,A,B,g,adj);
if (g[x]!=B[x]) {gc=gcd(gc,g[x]);}
tt+=A[x];
}
}
gc=gcd(gc,tt);
gc=gcd(gc,B[node]);
g[node]=gc;
}
void solve() {
long long N; cin >> N;
vector<long long> A; A.push_back(-1);
vector<long long> B; B.push_back(-1);
vector<vector<long long>> adj(N+1);
for (long long i = 0; i < N; i++) {
long long a; cin >> a;
A.push_back(a);
}
for (long long i = 0; i < N; i++) {
long long a; cin >> a;
B.push_back(a);
}
for (long long i = 0; i < N-1; i++) {
long long a, b; cin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
vector<long long> g(N+1); //init to 0 for identity gcd
dfs(1,0,A,B,g,adj);
long long aa = 0;
for (long long i = 1; i <= N; i++) {aa+=((B[i]-A[i]-1)/g[i])*g[i]+A[i];}
cout << aa << endl;
}
int main() {
long long T; cin >> T;
while (T--) {solve();}
}
We only need to keep one occurrence of every value $$$1,2,\ldots,n$$$. What can we do with every other occurrence?
Let $$$t_i$$$ be the arrival position of the occurrence of $$$i$$$ which stays in the final deque. When can $$$i$$$ be inserted without a malfunction?
An element can be inserted normally exactly when $$$t_i$$$ is a prefix minimum or a suffix minimum of $$$t_1,t_2,\ldots,t_n$$$.
Fix the position of the global minimum. The prefix minima and suffix minima can be optimized separately.
If some value from $$$1$$$ to $$$n$$$ never appears, the answer is $$$-1$$$. Otherwise, choose one occurrence of each value to keep. Every unused occurrence can simply be pushed to an end and immediately removed from that same end.
Let $$$t_i$$$ be the position of the chosen occurrence of $$$i$$$. We can push $$$i$$$ to the front normally exactly when every chosen value which arrived earlier is larger than $$$i$$$, or $$$t_i \lt \min(t_1,\ldots,t_{i-1})$$$. Similarly, we can push it to the back exactly when $$$t_i \lt \min(t_{i+1},\ldots,t_n)$$$. Thus, a value avoids a malfunction exactly when $$$t_i$$$ is a prefix minimum or a suffix minimum. The global minimum is counted in both, so if there are $$$L$$$ prefix minima and $$$R$$$ suffix minima, we keep $$$L+R-1$$$ values for free.
Now optimize the prefix minima. Process the values $$$1,2,\ldots,n$$$. Let $$$dp[p]$$$ be the maximum number of prefix minima so far when the smallest chosen arrival position is $$$p$$$. For an occurrence at position $$$t$$$, making it the new minimum gives $$$new[t]=1+\max_{p \gt t}dp[p]$$$. All of these transitions must be calculated before adding the states for the current value.
An old state with minimum $$$p$$$ can stay unchanged only if the current value has some occurrence after $$$p$$$. If $$$last_i$$$ is its last occurrence, every state with $$$p \gt last_i$$$ must therefore be deleted. For value $$$1$$$, every occurrence simply starts with value $$$1$$$.
After all values are processed, let $$$L[p]$$$ be the best number of prefix minima whose global minimum is at position $$$p$$$. Run the same DP with the values in reverse order to get $$$R[p]$$$ for suffix minima. For a fixed $$$p$$$, the two sides can be combined independently, sharing only the global minimum itself. Therefore, the maximum number of values which avoid a malfunction is $$$\max_p(L[p]+R[p]-1)$$$, and the answer is $$$n-\max_p(L[p]+R[p]-1)$$$.
Store the DP in a segment tree. For an occurrence $$$t$$$, the transition needs the maximum on $$$(t,m]$$$. After calculating all transitions for the current value, clear the suffix after $$$last_i$$$ and insert the new states.
A lazy segment tree supports the suffix clear and range maximum queries in $$$O(\log m)$$$, so the total complexity is $$$O(m\log m)$$$.
#include <bits/stdc++.h>
using namespace std;
struct lst { //cur range add range max, change accordingly, no need for l,r in range add range mx
vector<int> seg;
vector<bool> tg;
vector<int> lz;
int sz = 1;
int id = 0; //change sent
int acc(int x, int y) {return max(x,y);} //other more complex lst can do range set and range add
void pull(int n) {seg[n]=acc(seg[n<<1],seg[(n<<1)|1]);}
void apply(int n, int l, int r, int v) {seg[n]=v; tg[n]=true; lz[n]=v;} //if something else, change id, acc, apply, and how lz accumulates/replaces in push
void push(int n, int l, int r) {if (!tg[n]) {return;} tg[n]=false; apply(n<<1,l,(l+r)/2,lz[n]); apply((n<<1)|1,(l+r)/2+1,r,lz[n]); lz[n]=0;}
lst(vector<int> A) { //inp 0 index
while (sz<A.size()) {sz<<=1;}
seg.assign(2*sz,id);
tg.assign(2*sz,false); //in case 0 is a range set
lz.assign(2*sz,0);
for (int i = 0; i < A.size(); i++) {seg[sz+i]=A[i];}
for (int i = sz-1; i >= 1; i--) {pull(i);}
}
int qq(int n, int l, int r, int sl, int sr) {
if (sl>r||sr<l) {return id;}
if (l<=sl&&sr<=r) {return seg[n];}
push(n,sl,sr);
return acc(qq(n<<1,l,r,sl,(sl+sr)/2),qq((n<<1)|1,l,r,(sl+sr)/2+1,sr));
}
void uu(int n, int l, int r, int sl, int sr, int v) {
if (sl>r||sr<l) {return;}
if (l<=sl&&sr<=r) {apply(n,sl,sr,v); return;}
push(n,sl,sr);
uu(n<<1,l,r,sl,(sl+sr)/2,v);
uu((n<<1)|1,l,r,(sl+sr)/2+1,sr,v);
pull(n);
}
int q(int l, int r) {return qq(1,l,r,1,sz);}
void u(int l, int r, int v) {uu(1,l,r,1,sz,v);}
};
void solve() {
int N, M; cin >> N >> M;
vector<int> A;
for (int i = 0; i < N; i++) {
A.push_back(i+1);
}
vector<vector<int>> tt(N+1);
vector<int> ndp1(M+1);
for (int i = 1; i <= M; i++) {
int a; cin >> a;
tt[a].push_back(i);
}
for (int i = 1; i <= N; i++) {
if (tt[i].empty()) {cout << -1 << endl; return;}
}
vector<int> ii(M+1); // one sentinel at end so no RE
lst dp1(ii);
bool f = true;
for (auto x : A) {
for (auto t : tt[x]) {
int rr = dp1.q(t+1,M+1);
ndp1[t]=(rr?rr+1:rr+(f));
}
for (auto t : tt[x]) {
dp1.u(t,t,ndp1[t]);
}
dp1.u(tt[x].back()+1,M+1,0);
if (f) {f=false;}
}
vector<int> ndp2(M+1);
reverse(A.begin(),A.end());
lst dp2(ii);
f=true;
for (auto x : A) {
for (auto t : tt[x]) {
int rr = dp2.q(t+1,M+1);
ndp2[t]=(rr?rr+1:rr+(f));
}
for (auto t : tt[x]) {
dp2.u(t,t,ndp2[t]);
}
dp2.u(tt[x].back()+1,M+1,0);
if (f) {f=false;}
}
int aa = 0;
for (int i = 1; i <= M; i++) {aa=max(aa,dp1.q(i,i)+dp2.q(i,i)-1);}
cout << N-aa << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}
We can also use a normal segment tree together with a set of active positions. Whenever a state with position greater than $$$last_i$$$ becomes invalid, remove the largest such position from the set and set its segment tree value to $$$0$$$.
Each position is inserted once and deleted at most once in one pass, so there are only $$$O(m)$$$ deletions in total. The total complexity is again $$$O(m\log m)$$$.
#include <bits/stdc++.h>
using namespace std;
struct tri { //inp zero index vector, transformed to 1 index
vector<int> s;
int sz = 1;
tri(vector<int> &A) {
while (sz<A.size()) {sz<<=1;}
s.assign(2*sz,0);
for (int i = 0; i < A.size(); i++) {s[i+sz] = A[i];}
for (int i = sz-1; i >= 1; i--) {s[i]=max(s[i<<1],s[(i<<1)|1]);}
}
void u(int i, int x) {
int p = sz+i-1; s[p] = x;
for (p>>=1; p; p>>=1) {s[p]=max(s[p<<1],s[(p<<1)|1]);}
}
int aa(int n, int l, int r, int sl, int sr) {
if (l<=sl&&sr<=r) {return s[n];}
else if (sr<l||sl>r) {return 0;}
else {return max(aa(n<<1,l,r,sl,(sl+sr)>>1),aa((n<<1)|1,l,r,((sl+sr)>>1)+1,sr));}
}
int q(int l, int r) {return aa(1,l,r,1,sz);}
};
void solve() {
int N, M; cin >> N >> M;
vector<int> A;
for (int i = 0; i < N; i++) {
A.push_back(i+1);
}
vector<vector<int>> tt(N+1);
vector<int> ndp1(M+1);
for (int i = 1; i <= M; i++) {
int a; cin >> a;
tt[a].push_back(i);
}
for (int i = 1; i <= N; i++) {
if (tt[i].empty()) {cout << -1 << endl; return;}
}
vector<int> ii(M+1); // one sentinel at end so no RE
tri dp1(ii);
set<int> act;
bool f = true;
for (auto x : A) {
for (auto t : tt[x]) {
int rr = dp1.q(t+1,M+1);
ndp1[t]=(rr?rr+1:rr+(f));
}
for (auto t : tt[x]) {
dp1.u(t,ndp1[t]);
act.insert(t);
}
while (!act.empty()&&(*act.rbegin()>tt[x].back())) {dp1.u((*act.rbegin()),0); act.erase(*act.rbegin());}
if (f) {f=false;}
}
vector<int> ndp2(M+1);
act.clear();
reverse(A.begin(),A.end());
tri dp2(ii);
f=true;
for (auto x : A) {
for (auto t : tt[x]) {
int rr = dp2.q(t+1,M+1);
ndp2[t]=(rr?rr+1:rr+(f));
}
for (auto t : tt[x]) {
dp2.u(t,ndp2[t]);
act.insert(t);
}
while (!act.empty()&&(*act.rbegin()>tt[x].back())) {dp2.u((*act.rbegin()),0); act.erase(*act.rbegin());}
if (f) {f=false;}
}
int aa = 0;
for (int i = 1; i <= M; i++) {aa=max(aa,dp1.q(i,i)+dp2.q(i,i)-1);}
cout << N-aa << endl;
}
int main() {
int T; cin >> T;
while (T--) {solve();}
}








Update the announcement :3
all the code sections are empty. are you waiting until after the hacking, or is this a mistake?
waiting until after the hacking
I was also thinking about this.
There's NO CODE!
Sigma round, loved so much. But not C >:(
Oh my, I'm to cute. Signed, Bichup
C is actually hard
Congrats on expert!! Well deserved.
Thanks! Actually, im tried to stay at specialist, as long as i can. I think you will understand why in, 1-2 (max. 3) months.
May I ask what the main reason is? I imagine there is additional pressure to perform with the expert tag and the inability to officially participate in Div. 3 contests, are there other drawbacks?
Sorry, i cant "publish" the reason)
For H, instead of a segtree, we can use a BIT for easier implementation: https://codeforces.me/contest/2266/submission/391534225 Finding maximum over (t,m] is the same as finding maximum on (0,m-t]
nice!
had a ton of fun solving F :D, my bound for the binary search was [0,n+60] which makes it a bit easier to implement than having it bound by mx, and it's pretty easy to prove. was scared I didn't handle the overflow well but I guess it was just 1 if lol
I solved F after the contest but used the bounds
[mxValue -> (mxValue + 32)]. Just iterate over this range and get the result. My proof is : if I want the answer to bemx + ithen I need all the values in range[0-mxValue]to have frequency atleast(1 << (i - 1)). And as the max frequency is1e9so answer will not be greater thanmxValue + log2(1e9)I can’t remember the last time a Div 3 contest rekt me this hard.
After looking at the editorial, I actually like this contest.
Also, my post contest discussion stream here. ABCEDFG is the order.
D and E had me STRESSED. Glad I succeeded in solving them, and props to you WorldWarV for this contest! The problems I managed to solve had very elegant solutions, which I appreciate.
I solved C using dp
Submission
Likewise
Can u explain the logic?
Notice that s1 can never change (As
s[i]= (bitwise | or &) ofs[1], s[2], ... s[i]) (Put i = 1 in that equation to prove it)We want the string to be sorted in non-dec order so we know that if
s[i - 1]was 0, thens[i]can be both 0 or 1 (both possibilities) whereas ifs[i - 1]was 1, thens[i]must equal 1 (ifs[i]= 0, then it becomes unsorted, defeating our purpose)We will go step by step trying all possibilities through recursion
We will try to go through ALL POSSIBILITIES and find the minimum operations out of them.
Then memoize it (just store the values of the already calculated function calls so that we can save time).
You can just track the zeroes and ones that appear before the current index and after the current index, precalculate the total zeroes in advance.
I solved E after the contest. I didn't use DP I brute-forced the solution for each number in the array by factorizing it, and then found the formula for how many operations it will cost if I want to remove factor x from ai
could you please explain your approach I want to know
Let
abe some number that we want to reduce such thata <= kOne operation allows us to remove a prime number from a
We know that any number is the product of some prime numbers.
So assume a =
p1 * p2 * p3 * p4 * p5Let's say that we choose to remove
p1,p2,p3fromabecause we know thatp4 * p5 <= kNow all we need to know is the number of operations required to make
aand all the numbers it produced equal top4 * p5We start with
awhich is(p1 * p2 * p3 * p4 * p5)We divide it by
p1and now we havep1instances of(p2*p3*p4*p5)andcost+=1Now we divide each one of these new instances by
p2and we end up withp1 * p2instances andcost+=p1Now we also divide these
p1 * p2instances byp3, and we end up withp1 *p2 *p3instances andcost+=p1*p2So in order to remove
p1,p2, andp3, it cost us1 + p1 + p1*p2.So I first precomputed these costs for all numbers from 1 to 2e5 and then I tried all valid possible subsets of primes to remove
I had the similiar intution but couldnt think of anything.That is really a good approach man
I looked at H a bit differently, i.e. fix the start position and optimizing for the number of prefix maximums and prefix minimums.
Since these two sequences are independent excluding the starting element, we can optimize them individually.
For the prefix maximum case, if we want to add a value at position $$$j$$$ to the sequence ending at position $$$i$$$, we need to ensure that all values in $$$[b_i + 1, b_j - 1]$$$ is in $$$b[j + 1, n]$$$.
That way we can propagate from $$$j$$$ to $$$i$$$ by considering the minimum $$$b_i$$$ to be the first value not appearing in $$$b[j, n]$$$ that were less than $$$b_j$$$.
The same method can be used for the prefix minimum case.
Problems with easier implementations but harder ideas are so orz, one of my favorite contests so far
Nice round! Problem E was definitely easier than D if you know prime factors
Dealing with bigness of numbers in F was such a headache for me :(
A-B very easy
C standard prefix
D This felt very hard, All i could think of was sort with A[i]-i but couldn't do anything beyond it
E Easy dp with sieve
I didn't want to look at the editorial for D, after maybe 5 hours of brainstorming, I looked at your comment, and that was enough.
A[i]-i is the invariant that I didn't think of
This was my first contest, I want to know when the rating update happens??
hey same
DIV 3 or DIV 4 takes 2-3 days to update points.
C can also be modelled using easy dp
yup bro but i did it in 4d dp dont ask me why i also dont know why i overcomplicated this
Great Contest.Bob and Alice fought again BTW
Alice and Bob are the main villains of Codeforces.
Auto comment: topic has been updated by WorldWarV (previous revision, new revision, compare).
Well, solved till 5th question
Confortable till 4th though Thinking spf and reccursiveness was the coolest part
hell C
Yeah, realizing the solution was brute force and being forced to use prefix sums on a div 3 C is tough.
yea
Also what do you mean C is hell, you literally solved D and E, basically you're the expert and I'm the newbie.
if you read constantly and wanna solve it C is much more hard than them
I solved C using dp :) 391473244
E was a good problem:)
If i were to be honest, the difficulty curve of the problems were kinda inconsistent, for example i would personally say that D was harder than E but that might just be my skill issue. (Also the tutorial for d is somewhat vague too) Overall it was a great contest tho!
Felt more like a div 2 than a div 3, of course problem D and E would be easier than div 2, but first 3 weren't really easier.
Here is my $$$O(n^\frac{4}{3} \log{n})$$$ solution for Bonus E.
Firstly, it can be noticed that the problem can be solved separately for each element.
Now for some element $$$a_i$$$, we can find values of $$$f(1), f(2), f(3), ..., f(n)$$$ in $$$O(n)$$$ by the following method:
We'll have a set (or a min heap over costs) $$$S_i$$$, which will store all the active nodes that sprouted out of $$$a_i$$$. Initially $$$S_i$$$ only contains $$$a_i$$$.
Now we'll have a pointer move right to left; that is, it would initially be set to $$$n$$$ and would move towards $$$1$$$.
The pointer will continue to move until it reaches a point of active node, the first such point would be $$$a_i$$$ itself, as we reach it we'll remove it from $$$S_i$$$. Then, we'll add all the direct factors of $$$a_i$$$ as nodes containing the cost to transform $$$a_i$$$ into them, and add each of them to $$$S_i$$$ [Where, $$$v$$$ is called a direct factor of $$$u$$$, if $$$\frac{u}{v}$$$ is a prime]. And we'll repeat the process so on as the pointer moves. [If on reaching a node, an already active node that is direct factor of current node is to be modified, then we'll choose the better (minimum) cost for it out of its current cost and the cost we're passing through the current node]
Now to calculate the value of $$$f(x)$$$, we'll simply wait for the pointer to reach $$$x$$$, because at this point the node with minimum cost in $$$S_i$$$ would be the value of $$$f(x)$$$.
Doing the above naively for each element separately, would result in $$$O(n^2 \log{n})$$$, hence, we'll solve the above problem in one sweep in parallel for all the $$$a_i$$$ simultaneously.
The intended time complexity for the bonus is $$$O(n\log n)$$$!
Shouldn't this be $$$O(n\log^2(n))$$$ since the total number of divisors from 1 to n is $$$O(n\log(n))$$$?
I went with a very crude approximation, by taking ~$$$O(n^{1/3})$$$ factors for a number comparable to $$$n$$$. And since the multiset has $$$n$$$ elements; We'll get total $$$O(n^{4/3})$$$ nodes, and each node costs $$$O(\log{n})$$$ to activate or deactivate.
My bad, $$$O(n \log^2{(n)})$$$ is much more accurate bound for it.
D got AC during contest but shows TLE now :(
Very good contest
Can anyone explain the solution of
problem Gin easy terms and words?My rough solution for Bonus E.
First compute dp values for $$$k = 1$$$.
then for $$$k = 2$$$, $$$dp[2]$$$ is changed to 0.
This change will affect only to multiples of 2.
Naively recompute dp values for them.
And update the total sum if updated value is present in $$$a$$$.
repeat this for $$$k = 3, 4, \dots, n$$$.
This is $$$O(n\log{n}\log{\log{n}})$$$ because of harmonic lemma.
Maybe?
Close! The intended solution is
$$$O(n\log n)$$$
I only see the intended time complexity in the hint. Could you please check.
Bonus for problem F
Idea come from bitwise,assume that input range x $$$\in [0,n)$$$ and every number with frequencey $$$10^9$$$,i define $$$n$$$ as position $$$0$$$,$$$n+1$$$ as position $$$1$$$ and so on,$$$n+i$$$ equal to position $$$i$$$,now i observe something interesting if you regard the reverse binary representation as a decimal number then the decimal number is the number of times for the x $$$\in [0,n)$$$ need to deduce to form,for example,if look like "011" the reverse is "110" which is $$$6$$$,so you need $$$6$$$ times to get number $$$n+1$$$ and $$$n+2$$$ the proof is simple,if we let any number $$$x\lt n$$$ reduce $$$1$$$ then the number of position $$$0$$$ will increase $$$1$$$,this act like a binary adding operation.
So let the maximum number be $$$n+k-1$$$ then $$$1+2^1+2^2+..+2^k=2\cdot 10^{14}$$$,thus $$$k\approx 48$$$,why $$$2\cdot 10^{14}$$$?because every number greater than $$$n+50$$$ is useless and we can make them into $$$0$$$ so this is a approximation,in real situation it can't reach
Explanation for G AC code
What you need?:$$$\text{Bezout indentity,dfs,gcd}$$$
First we reduce the problem,i don't know how to construct the answer then i let $$$y_i$$$ is the maximum number $$$x_i$$$ can reach,then $$$ans=\sum y_i$$$ .
Now,i observe something interesting,$$$y_i$$$ is independent,why?Let $$$u$$$ be the parent of $$$v$$$,then i can make $$$x_u$$$ to $$$y_u$$$ first,then after that no matter how i change $$$x_v$$$,it won't affect $$$x_u=y_u$$$
from step $$$2$$$,the problem reduce to how to maximum $$$x_i$$$ to $$$y_i$$$,now i suddenly observe something,let set $$$A=\{s_v\}$$$ which $$$s_v=\sum x_v$$$ for some moment,obviously $$$|A|$$$ (size of the set) is finite,then the $$$(x_i=a_i + c_0\cdot b_i + c_1\cdot s_1 + ... )\mod b_i$$$,if you see this form you must be sensitive,because this is related to the general bezout identity,define $$$g=\gcd(b_i,s_v)$$$ then you can see that no matter i reduce how many times of $$$b_i$$$ or increase how many times of $$$s_v$$$ ,in the kernel ,always increase/decrease some $$$g$$$ and bezout identity state that i always exist such a set of coefficient such that $$$(c_0\cdot b_i + c_1\cdot s_1 + ... )=g\mod b_i$$$,for example if $$$s_1=10\cdot g$$$ and $$$b=20\cdot g$$$ then if i increase $$$1$$$ time $$$s_1$$$ and decrease $$$1$$$ time $$$b$$$ then result is $$$+10\cdot g - 20\cdot g=-10\cdot g$$$,in modular i can use add arithmetic to simulate minus arithmetic,for example if $$$b=20\cdot g$$$ and current $$$x_i$$$ be $$$constant+10\cdot g$$$,if i want minus $$$3\cdot g$$$,i can directly add $$$17\cdot g$$$
Now everything is almost clear,$$$x_i=a_i + k\cdot g$$$ and $$$k$$$ is some constant,i observe that if $$$a_i\ge k$$$ then $$$a_i$$$ also produce some of the $$$k$$$,thus let $$$r_i = (a_i \mod g)$$$ then $$$x_i = (r_i+c\cdot g)\mod b_i$$$ and $$$c$$$ is some constant,how to maximize this equation?Remember that $$$b_i$$$ is a multiple of $$$g$$$ thus let $$$b'=\frac{b}{g}$$$ then apparently $$$c\ge b'$$$ is useless it will cycle back,so we can ensure that $$$0\le c\lt b$$$ then i greedily pick the largest one and i found that $$$r_i+(b'-1)\cdot g=r_i+b-g\lt b_i$$$,so we can conclude that for every vertex $$$i$$$ the maximum $$$x_i$$$ it can reach is $$$r_i+b-g_i$$$ and $$$r_i=a_i \mod b_i$$$ and $$$g_i=\gcd(b_i,s_v)$$$
How to construct answer?Actually we don't need $$$s_v$$$,we need $$$g_v$$$,Define $$$u$$$ as the parent of $$$v$$$ then $$$s=\sum a_v$$$,let me remind you what $$$g_i$$$ meaning for,$$$g_i$$$ is the change of every operation in $$$x_i$$$,in other word $$$x_i$$$ always increase/decrease $$$g_i$$$,so we can say that for $$$s_v$$$ of $$$u$$$ , we have $$$s_v=s+\sum c_v\cdot g_v$$$ and $$$c_v$$$ is some constant,tell me what's this form?Bezout identity right?So let $$$g_i=\gcd(b,s,g_v)$$$ then no matter i increase how many times of $$$b,s,g_v$$$ the kernel is i always increase/decrease $$$x_i$$$ some $$$g_i$$$
More clean Max-segment tree solution for H AC code
You can learn from author : Al.Cash
I took a different perspective on H: it can be seen as a longest increasing/decreasing subsequence variant. Looking just at the low value side: observe that for a given value $$$b_i$$$, we can only ever avoid a malfunction if $$$1,2,\cdots, b_i-1$$$ are all present in $$$b$$$ at positions $$$ \gt i$$$; filter out all items for which this doesn't hold. On the remaining items, observe that a decreasing subsequence of length $$$k$$$ with first chosen value $$$v$$$ corresponds to insertions on the left side going from $$$v$$$ to $$$1$$$: for any un-selected element we have it malfunction at its last possible time, and our filtration rule guarantees we will be able to do this. The standard LIS approach going backwards over $$$b$$$ gives the full tradeoff frontier between $$$v$$$ and $$$k$$$; combine this with the mirrored high-value solution to find an optimal cutoff starting value. Note that this approach also makes it easy to explicitly construct the optimal series of choices.
D was really witty question!!
I have a doubt in problem E where in the given testcase where
12 3 12 10 9 8 7 6 5 4 3 2 1 12
here I think we can do it 12 operations because if we select our final multiset elements to be {1, 2, 4} then
12 : p=3 x/p=4 -> 1 ops12 : p=3 x/p=4 -> 1 ops10 : p=5 x/p=2 -> 1 ops9 : p=3 x/p=3 each p=x/p=3 x/p=1 -> 4 ops8 : p=2 x/p=4 -> 1 ops7 : p=7 x/p=1 -> 1 ops6 : p=3 x/p=2 -> 1 ops5 : p=5 x/p=1 -> 1 ops3 : p=3 x/p=1 -> 1 opsso the minimum operation is 12 but in the test case it is mentioned as 15. please correct me if I am doing wrong somewhere
You need to use prime divisor,for example your change of $$$12$$$ is $$$12\rightarrow 4 \rightarrow 1$$$ but you can't make $$$4$$$ to $$$1$$$ in one step because $$$4$$$ is not prime divisor
learnt something new from D and E after a long enough hiatus from CF, thanks
G is clever, love it :D