Problem Idea: 36champ
Solution Idea: 36champ
What if the meeting location is fixed?
If the meeting location is fixed, the answer is max(the number of people to the left of that position, the number of people to the right of that position.
This can be solved in $$$O(n^2)$$$ by iterating through all position that has at least one person on it. This problem can also be solved in $$$O(n\log n)$$$ by sorting and setting the meeting position to the median of all positions.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
cin >> t;
while(t-->0)
{
int n;
cin >> n;
vi a(n);
for(int i=0; i<n; i++) cin >> a[i];
sort(a.begin(), a.end());
int cnt = 0;
for(int i=0; i<n; i++) if(a[i] != a[n-1-i]) cnt++;
cout << cnt / 2 << "\n";
}
}
Problem Idea: 36champ, Proof_by_QED
Solution Idea: Proof_by_QED
If we know the answer to the $$$i$$$-th position, what can we say about the answer to the $$$(i + 1)$$$-th position?
Suppose that we can just move the frosting freely. What is the maximum height the frosting can be while keeping it leveled?
Using the first two hints, we hypothesize that the answer for the first $$$i$$$ position of the cake is min(prefix average). Now, we will show that this is true by induction.
Base Case ($$$i = 1$$$): Since there is only one position, the answer is $$$a_1$$$.
Inductive Step: Suppose that the answer for the $$$i$$$ position is correct, now consider the first $$$i + 1$$$ positions. Since we have $$$\sum_{j=1}^{i+1} a_j$$$ units of frosting, the maximum height is $$$\frac{\sum_{j=1}^{i+1} a_j}{i + 1}$$$. Combining this with hint 1 and the inductive hypothesis, the answer is $$$\min_{k=1}^{i+1} \frac{\sum_{j=1}^{k+1} a_j}{k + 1}$$$.
This problem can be solved in $$$O(n)$$$.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
cin >> t;
while(t-->0)
{
int n;
cin >> n;
vll a(n);
for(int i=0; i<n; i++) cin >> a[i];
ll ans = 1e9, sum = 0;
for(int i=0; i<n; i++)
{
sum += a[i];
ans = min(ans, sum / (i + 1));
cout << ans << " ";
}
cout << "\n";
}
}
Problem C1, C2 — Seating Arragement
Problem Idea: 36champ
Solution Idea: 36champ, Proof_by_QED
There are two solutions to this problem presented below.
If we fixed the number of ambiverts that behave as introverts, what is the best way to assign who is introverted/extroverted?
It is always better to assign the prefix of ambiverts as introverts and the rest as extroverts, because if the number of introverts is fixed, then it is better to have introverts as early as possible.
For this subtask, it is possible to brute-force the number of ambiverts acting as introverts and find the answer in $$$O(n^2)$$$.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll s, t;
ll eval(string &S, int m)
{
ll T = 0, ans = 0;
for(char c: S)
{
if(c == 'I')
{
if(T < t)
{
T++;
ans++;
}
}
else if(c == 'E')
{
if(ans < T * s) ans++;
}
else
{
if(m-->0)
{
if(T < t)
{
T++;
ans++;
}
}
else
{
if(ans < T * s) ans++;
}
}
}
return ans;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while(T-->0)
{
int n;
cin >> n >> t >> s;
string S;
cin >> S;
int l = 0, r = 0;
for(char c: S) if(c == 'A') r++;
ll ans = 0;
for(int i=l; i<=r; i++) ans = max(ans, eval(S, i));
cout << ans << "\n";
}
}
Assigning more ambiverts as introverts has a diminishing return.
Let $$$f(i)$$$ be the maximum number of people seated if the first $$$i$$$ ambiverts act as introverts. If $$$f(i + 1) \lt f(i + 2)$$$, what is the relation ship between $$$f(i)$$$ and $$$f(i + 1)$$$.
Let $$$f(i)$$$ be the maximum number of people seated if the first $$$i$$$ ambiverts act as introverts. We will first prove that if $$$f(i + 1) \lt f(i + 2)$$$, then $$$f(i) \lt f(i + 1)$$$.
Consider the situation where everyone is either an introvert or an extrovert, then we can simply use the greedy algorithm to solve this situation.
Suppose that $$$f(i + 1) \lt f(i + 2)$$$, then there are two possible scenarios:
Case 1: The $$$(i + 2)$$$-th ambivert is not seated when they are extroverted, but is seated when they are introverted.
Thus, when the first $$$i$$$ or $$$i + 1$$$ ambiverts are introverted, only $$$i$$$ or $$$i + 1$$$ tables are all seated, and the rest of the tables are empty. Thus, $$$f(i) \lt f(i + 1)$$$.
Case 2: The $$$(i + 2)$$$-th ambivert is seated when they are extroverted, and is still seated when they are introverted.
Since $$$f(i + 1) \lt f(i + 2)$$$, we know that someone previously unseated has to take the $$$(i+2)$$$-th ambivert's original seat, and since this person is originally unseated, this means the first $$$i + 1$$$ tables have to be fully seated. Therefore, $$$f(i) \lt f(i + 1)$$$.
Next, since we know that $$$f$$$ is strictly increasing before it plateaus/decreases. We can find the peak by finding the least $$$i$$$ that has $$$f(i) \geq f(i + 1)$$$.
Using binary search to find the optimal number of ambiverts acting as introverts reduces the time complexity of this problem down to $$$O(n \log n)$$$.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll s, t;
ll eval(string &S, int m)
{
ll T = 0, ans = 0;
for(char c: S)
{
if(c == 'I')
{
if(T < t)
{
T++;
ans++;
}
}
else if(c == 'E')
{
if(ans < T * s) ans++;
}
else
{
if(m-->0)
{
if(T < t)
{
T++;
ans++;
}
}
else
{
if(ans < T * s) ans++;
}
}
}
return ans;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while(T-->0)
{
int n;
cin >> n >> t >> s;
string S;
cin >> S;
int l = 0, r = 0;
for(char c: S) if(c == 'A') r++;
while(l < r)
{
int m = (l + r) / 2;
int x = eval(S, m), y = eval(S, m + 1);
if(x < y) l = m + 1;
else r = m;
}
cout << eval(S, l) << "\n";
}
}
If we fixed the number of ambiverts that behave as introverts, what is the best way to assign who is introverted/extroverted?
If there are no ambiverts, we can solve this problem greedily. How can we use the greedy algorithm here?
We will process each person one by one and keep track of the minimum and maximum number of tables occupied.
Let $$$l$$$, $$$r$$$, and $$$ans$$$ be the minimum, maximum number of tables occupied, and the maximum number of people seated, respectively.
If we encounter an introvert, we want to assign them an empty table. Therefore, if $$$l \lt t$$$, we increase $$$l, r$$$ by $$$1$$$ capping at $$$t$$$ and increase $$$ans$$$ by $$$1$$$.
If we encounter an extrovert, we want to assign them a non-empty table. Therefore, we can increase $$$ans$$$ by $$$1$$$ if there is an empty seat ($$$r * s \gt ans$$$). You also need to make sure that after this person is seated, $$$l$$$ is updated accordingly (increased by $$$1$$$ if $$$l * s \lt ans$$$ now).
If we encounter an ambivert, we have to execute both strategies above.
This solution only takes $$$O(n)$$$.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while(T-->0)
{
ll n, s, t;
cin >> n >> t >> s;
string S;
cin >> S;
ll l = 0, r = 0, ans = 0;
for(char c: S)
{
if(c == 'A')
{
if(t * s == ans) continue;
ans++;
if(ans > l * s) l++;
r = min(t, r + 1);
}
else if(c == 'I')
{
if(l == t) continue;
ans++;
l++;
r = min(t, r + 1);
}
else if(c == 'E')
{
if(ans == r * s) continue;
ans++;
if(ans > l * s) l++;
}
}
cout << ans << "\n";
}
}
Problem D — Magical Tiered Cake
Problem Idea: 36champ
Solution Idea: 36champ
Can you solve the Tower of Hanoi?
If $$$a_i \geq i$$$, then it is impossible because there cannot be at least $$$i$$$ rings on the $$$i$$$-th smallest ring in the first place.
If $$$a_i \lt i$$$ for all $$$i$$$, it is always possible.
If possible, we can move the cake in at most $$$2^n - 1$$$ moves with a recursive algorithm similar to the classic Tower of Hanoi.
Base Case ($$$1$$$ layer): Perform one move to move it from location $$$1$$$ to $$$3$$$.
Inductive step ($$$k$$$ layers): Let $$$f(i)$$$ be the number of moves to solve the first $$$i$$$ layers. By strong induction, $$$f(i) \leq 2 ^ i - 1$$$.
Case 1: $$$a_k = 0$$$
This takes $$$f(k - 1)$$$ moves to move the first $$$k - 1$$$ layers to location $$$2$$$, $$$1$$$ move to move the $$$k$$$-th layer to location $$$3$$$, and another $$$f(k - 1)$$$ moves to move the first $$$k-1$$$ layers to location $$$3$$$.
Total: $$$2 * f(k - 1) + 1 \leq 2 ^ k - 1$$$ moves
Case 2: $$$a_k \geq 1$$$
This takes $$$f(k - 1 - a_k)$$$ moves to move the first $$$k - 1 - a_k$$$ layers to location $$$2$$$, $$$1$$$ move to move the $$$k$$$-th layer to location $$$3$$$, $$$f(k - 1 - a_k)$$$ moves to move the first $$$k - 1 - a_k$$$ layers back to location $$$1$$$, and another $$$f(k - 1)$$$ moves to move the first $$$k - 1$$$ layers to location $$$3$$$.
Total: $$$2 * f(k - 1 - a_k) + f(k - 1) + 1 \leq 2 * f(k - 2) + f(k - 1) + 1 \leq 2 ^ k - 2 \leq 2 ^ k - 1$$$ moves.
Therefore, this problem can be solved in $$$O(2^n)$$$
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
int n;
vi a(20);
vvi op;
void moveall(int k, int s, int t)
{
if(k <= 0) return;
int u = 6 - s - t;
if(a[k - 1] == 0)
{
moveall(k - 1, s, u);
op.pb({k, s, t});
moveall(k - 1, u, t);
}
else
{
moveall(k - 1 - a[k - 1], s, u);
op.pb({k, s, t});
moveall(k - 1 - a[k - 1], u, s);
moveall(k - 1, s, t);
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while(t-->0)
{
cin >> n;
for(int i=0; i<n; i++) cin >> a[i];
bool ok = true;
for(int i=0; i<n; i++) if(a[i] > i) ok = false;
if(!ok)
{
cout << "NO\n";
continue;
}
cout << "YES\n";
moveall(n, 1, 3);
cout << op.size() << "\n";
for(vi p: op) cout << p[0] << " " << p[1] << " " << p[2] << "\n";
op.clear();
}
}
Problem E — Snaking Arrangement
Problem Idea: 36champ
Solution Idea: 36champ
Look at the anti-diagonals (bottom left -> top right).
There is a bijection between the snaking arrangement and the permutation of $$$[1, 2, \dots, n]$$$.
By looking at anti-diagonals of the grid, we can observe that the first anti-diagonal (just the top-left cell) only contains the snake of length $$$n$$$. Then, the next anti-diagonal contains the snake of length $$$n-1$$$ and $$$n$$$, and so on. Therefore, by looking at the $$$i$$$-th and $$$(i+1)$$$-th anti-diagonals, we know the relative position between the $$$(n - i)$$$-th snake and all snakes longer than it.
For example,
3 3 ?
? 3 3
? ? 3
has alternate diagonals 3, ? 3, ? 3 ?.
3 -> ? 3. Know that 2 is to the left of 3. ? 3 -> ? 3 ?. Know that 1 is to the right of 3.
This can now be solved comfortably in $$$O(n^2)$$$ or in $$$O(n)$$$ with more optimization.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const ll N = 1000000007;
#define MAX_N 200005
vll fac(MAX_N, 1);
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
for(int i=2; i<MAX_N; i++) fac[i] = (i * fac[i - 1]) % N;
int t = 1;
cin >> t;
while(t-->0)
{
ll n, k;
cin >> n >> k;
vvi D; vi d;
bool ok = true;
for(int i=0; i<k; i++)
{
ll s, r, c;
cin >> s >> r >> c;
//Starting Point Check
if(s / 2 + r + c != n + 1) ok = false;
vector<pii> V;
V.pb({r, c});
if(s != 1)
{
string S;
cin >> S;
for(char C: S)
{
if(C == 'R')
{
c++;
V.pb({r, c});
}
else
{
r++;
V.pb({r, c});
}
}
//Symmetry Check
for(int i=0; i<s/2; i++) if(V[i].second - V[i].first != V[s - i - 1].second - V[s - i - 1].first) ok = false;
}
//Info Handling
if(!ok) continue;
if(D.size() < s / 2 + 1)
{
D.resize(s / 2 + 1);
d.resize(s / 2 + 1);
}
for(int i=0; i<s/2+1; i++) D[i].pb(V[s/2-i].second);
d[s / 2] = V[0].second;
}
if(!ok)
{
cout << "0\n";
continue;
}
int x = D.size();
for(int i=0; i<x; i++) sort(D[i].begin(), D[i].end());
D.pb({});
ll ans = 1;
for(int i=0; i<x; i++)
{
if(!ok)
{
ans = 0;
continue;
}
bool dec = false;
int l = 0, k = 0;
while(l + k < D[i].size())
{
if(D[i][l + k] == d[i])
{
k++;
continue;
}
if(D[i][l + k] == D[i + 1][l])
{
if(dec)
{
ok = false;
break;
}
}
else if(D[i][l + k] - 1 == D[i + 1][l])
{
if(!dec)
{
if(l + k == 0 && d[i] == 0) ans *= D[i][l + k] - 1;
else if(l + k != 0 && d[i] == 0) ans *= D[i][l + k] - D[i][l + k - 1] - 1;
ans %= N;
}
dec = true;
}
else
{
ok = false;
break;
}
l++;
}
if(!dec)
{
if(d[i] == 0) ans *= n - i - D[i][l + k - 1];
ans %= N;
}
}
ans *= fac[n - x];
ans %= N;
cout << ans << "\n";
}
}
Problem Idea: 36champ
Solution Idea: 36champ
Extended Euclidean Algorithm
Formally, we have the system of equations:
$$$a * x_1 = k$$$
$$$a * x_2 + b * x_1 = k$$$
$$$a * x_3 + b * x_2 = k \dots$$$
where $$$x_i$$$ are non-negative integers.
If $$$k$$$ is not divisible by $$$gcd(a, b)$$$, then the answer is $$$0$$$.
Now, let's assume that $$$gcd(a, b) = 1$$$ since you can divide $$$a$$$, $$$b$$$, and $$$k$$$ by $$$gcd(a, b)$$$. If $$$a = b = 1$$$, then the answer is $$$n$$$.
Otherwise, we will compute $$$x_1$$$, $$$x_2$$$, ... until $$$x_i$$$ becomes negative or non-integer. ($$$x_{m+1}$$$ is not a non-negative integer).
So, we know that $$$a * x_{m + 1} + b * x_m$$$ can't be equal to $$$k$$$. Therefore, $$$x_{m + 1}$$$ is independent from $$$x_m$$$.
Next, we want to maximize the number of equations in the following form that you can solve all at the same time. $$$a * x_{m + 2} + b * x_{m + 1} = k$$$
$$$a * x_{m + 3} + b * x_{m + 2} = k$$$
$$$a * x_{m + 4} + b * x_{m + 3} = k \dots$$$
Looking at the first $$$2$$$ equations, if you can solve both of them, then $$$a * x_{m + 3} + b * x_{m + 2} = a * x_{m + 2} + b * x_{m + 1}$$$ or $$$a * (x_{m + 3} - x_{m + 2}) = b * (x_{m + 1} - x_{m + 2})$$$
Therefore, $$$b | x_{m + 3} - x_{m + 2}$$$ and $$$a | x_{m + 2} - x_{m + 1}$$$ Furthermore, $$$b | x_{m + 4} - x_{m + 3}$$$ and $$$a | x_{m + 3} - x_{m + 2}$$$ So, $$$b^2 | x_{m + 4} - x_{m + 3}$$$, $$$ab | x_{m + 3} - x_{m + 2}$$$ and $$$a^2 | x_{m + 2} - x_{m + 1}$$$. This can be extended further using induction.
Suppose $$$a \gt b$$$, consider $$$(a + b) * x_{m + 2} + b * (x_{m + 1} - x_{m + 2}) = (a + b) * x_{m + 2} + b * (a ^ v) * y$$$. If this can be equal to k when both $$$x_{m + 2}$$$ and $$$x_{m + 1} = a^v * y + x_{m + 2}$$$ are non-negative integers, then we can solve $$$v + 1$$$ equations at once.
If $$$k$$$ is divisible by $$$a + b$$$, then $$$v$$$ is infinite. Otherwise, $$$y$$$ is positive, so you can Binary Search for $$$v$$$. (Linear search should be fine too)
The $$$a \lt b$$$ case can be handled similarly.
After you have $$$m$$$ and $$$v$$$, you can use them to maximize your score.
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
// function to find the solution
ll gcd(ll a, ll b, ll &x, ll &y){
if(b == 0){
x= 1; y = 0;
return a;
}
ll x1, y1;
ll d = gcd(b, a%b, x1, y1);
x = y1;
y = x1 - y1*(a/b);
return d;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
cin >> t;
while(t-->0)
{
ll n, a, b, k;
cin >> n >> a >> b >> k;
ll g = __gcd(a, b);
if(k % g != 0)
{
cout << "0\n";
continue;
}
a /= g; b /= g; k /= g;
if(a == 1 && b == 1)
{
cout << n << "\n";
continue;
}
/// STEP 1
ll ans = 0;
if(k % a == 0)
{
ans++; n--;
ll x = k / a;
while(n > 0)
{
if(k - (x * b) < 0 || (k - x * b) % a != 0) break;
x = (k - x * b) / a;
ans++;
n--;
}
}
/// STEP 2
ll v = 0;
if(k % (a + b) == 0) v = 1e9;
else
{
if(a < b) swap(a, b);
/// SOLVE (a + b) x + b * a^v y = k
ll m = b;
while(true)
{
ll x, y;
gcd(a + b, m, x, y);
if(x < 0) {x += m; y -= a + b;}
x *= k; y *= k;
ll d = x / m;
x -= d * m; y += d * (a + b);
//cout << x << " " << y << "\n";
//getchar();
if(m / b * y + x < 0) break;
/// Secondary Check
bool ok = true;
ll x1 = x, x2 = m / b * y + x;
for(int _=0; _<v; _++)
{
if(a * x1 + b * x2 != k) ok = false;
if((k - b * x1) % a)
{
ok = false;
break;
}
x2 = x1;
x1 = (k - b * x1) / a;
}
if(!ok) break;
v++;
if(a > k / m) break;
m *= a;
}
}
//cout << "! " << v << "\n";
cout << ans + (n - (n + v) / (v + 1)) << "\n";
}
}








second
Thank you for the fast editorial
good contest. relatively fast editorial
misjudged the constraints on D
Why does ternary search not work on C2?
Because the function is not unimodal, the peak can be flat.
no, the function is unimodal, so ternary search can work even in flat peaks.
I don't think it is unimodal. The current proof that I have only show that it is strictly increasing then decreasing (not strictly decreasing). Therefore, there can be multiple plateaus and will mess up ternary search.
It works
How? What optimus said made sense ngl. If ur sure can you check my submission and tell me what i did wrong
Submission
I’m going to sleep and I am lazy so I’m not going to review your code, check submission above
Alr thanks
it works , mine solution is ternary search
Can we solve C1 by dp
yes
Yes, i did 2d dp
I also did 2D dp
https://codeforces.me/contest/2232/submission/376702136
I would be grateful if you could check my solution
i would love to but im garbage at python T_T
https://codeforces.me/contest/2232/submission/376683418 c++ dp solution
Oh that's nice acc. well done man!
Thanks, glad it helped!
honestly, i did not EVEN THINK anything about bruteforce, i thought of some sort of suffix greedy then my mind just went to 2d DP and i struggled like a dumbass for an hour straight lol
It's okay, mate. Just learn from the setbacks and keep moving forward.
Yes, I had $$$dp[i][u]$$$: max amount of people seated after processing the first $$$i$$$ people and having $$$u$$$ tables.
transition for I: $$$dp[i][u+1] = \max(dp[i-1][u]+1, dp[i-1][u+1])$$$
transition for E: $$$dp[i][u] = \max(dp[i][u], dp[i-1][u]+1)$$$
for A just consider both cases. And in transition, just be careful about not using more seats or tables than allowed.
submission link
Hey,
Why is the transition
dp[i][u+1] = max(dp[i-1][u] + 1, dp[i-1][u+1])
and not
dp[i][u+1] = max(dp[i-1][u] + 1, dp[i][u+1])?
Thanks.
got the logic on myself later
Im very sad that i did so poorly in a very cool contest, nonetheless congrats to the writers for such an amazing contest
Yes me too :(( it seemed really fun
I think I came up with the weirdest solution for C1 and C2 out of all the submissions. Glad that it worked :)
What was your solution? If you don't mind sharing?
First I precomputed the next occurrence of an introvert for every index of the string and stored it.
Then I iterated through the string always seating an introvert and extrovert whenever I could. For the case of ambivert there were two cases:
2.a) If the remaining count of unseated tables is greater than the remaining count of introverts, one table will go untouched, so it is clearly better for an ambivert to act as an introvert and open it.
2.b) If the remaining count of unseated tables is less than or equal to remaining count of introverts. This means that all of the tables will be opened regardless because there are enough introverts in the string. So, extroverts/ambiverts are more valuable now. So, we will make the ambivert an extrovert by default with the exception of one case, when, till the next occurrence of an introvert from that index, there are more extroverts/ambiverts than the amount of extroverts that can be currently seated(done using the pre-computed array). Because in that case, making our ambivert an extrovert wouldn't matter as some extroverts would be kicked out of the party before the next introvert occurs.
Hope that made sense, in short, we can just iterate through the array and decide on the fly whether an ambivert needs to be an extrovert or an introvert, and solve this problem in O(n).
Did you solve it in order of N time ?
I also had an intution but getting wrong answer everytime loll
Yes I did, see my submission and the explanation I gave above.
Bro thanks to you I got the intution and was able to solve it in my own later on
And How did you decide that the amibivert is going to be an introvert or an extrovert ?
Same soln
Exactly same soln!
Just that I didn;t think about that one exception case in 2.b) and just assigned the ambivert as an extrovert :(
Same I also forgot that one exception and still my code got accepted.
The thing is there are some missing test cases.
But mine was rejected
at test 9
i guess the order of conditions i put in A was the problem
You can look at the test where your code failed after the contest btw
yeah but the test case is somewhere around 289th test case of test 9. So that's not visible
I think the explanation for Case 2.b is missing something.
Consider this test case:
n = 16, x = 5, s = 3 IEIIAEEEIEEEEEEI
At the A, there are 2 unopened tables and enough free seats before the next I, so according to the explanation, A should act as an extrovert.
However, if A acts as an extrovert, the last I opens the final table at the very end of the sequence, so its remaining 2 seats are wasted because there are no people after it. If A opens the table earlier, those seats can be used by the later extroverts.
I tried this test case with your code, and it outputs 13, while I believe the correct answer is 15.
Am I missing some invariant, or is the explanation for Case 2.b incomplete?
My post contest discussion stream for A-D problems here
by when will ratings update?
C1 will be much easier if I don't overthink
can you help me to figure out the c1 question: test case : 11 3 1 4 1 5 9 2 6 5 3 5
how it's answer comes 5, by my calculation the minimum number group call would be 6.
is there any way to do C2 with some sort of exchange argument? or we stored "unplaced ambiverts" so far and when we hit an extrovert / introvert we can retroactively place them
yeah, you can heuristically place ambiverts as extroverts. Then if you get an extrovert and have no places for them you can move an ambivert to an introvert.
Thanks, I got an AC here: https://codeforces.me/contest/2232/submission/376724789
I also upsolved it with kindof exchange arguments :)
Here is my submission
Yes, it's a straight-forward application of the Time Travel in Greedy Algorithms. Checkout this blog for the idea, and this contest for more problems that use this idea.
https://codeforces.me/group/7Dn3ObOpau/contest/513385
Submission
thanks a lot!
Can someone describe the solution for E in more details?
I also find the editorial answer insufficient. The first thing the solution should do is create a anti-diagonal array. In the given example it will be
For each antidiagonal transition we find the number of ways a new snake could be added and multiply the answer by it. For a new snake that is present the answer is simply 1. Otherwise we find the number of ways it is possible to add element to
anti[i]to obtainanti[i+1]If
anti[i][j] != -1 && anti[i][j] == anti[i+1][j]the newly added?is at place>jIf
anti[i][j] != -1 && anti[i][j] == anti[i+1][j+1]the newly added?is at place<=jI was only able to solve E after reading your comment. Thanks!
could someone please tell me, why it is failing for problem B
I think you need
Your solution could have make the answer increasing which is wrong.
could you please share one example test case where it will be failing?
a={2,10,1}, your code will output a increasing sequence as answer
got it now thanks for your help guys
why the answer in the problem A with sorting approach is cnt/2 not ceil(cnt/2)?
No idea, I solved it using two pointer method.
It doesn't matter because cnt is always even. If $$$a_i \neq a_{n-i+1}$$$, then $$$a_{n-i+1} \neq a_{n-(n-i+1)+1}$$$ too.
Can someone explain C2 in more detail? I'm not understanding either of the alternate solutions. I bricked it lol
Initially, treat all ambiverts as extroverts. That is, if the next friend is an introvert, place them at an empty table, and if the next friend is an extrovert or an ambivert, place them at a partially-full table.
Now consider the case where our next friend is an extrovert, but we have no partially-full tables to assign them to. It would have been nice if we had the foresight to place a previous ambivert instead at an empty table, opening up a seat for this extrovert, and also creating a new partially-full table for any future extroverts. This is possible if and only if there exists a previous ambivert which we treated as an extrovert, and there is at least one empty table remaining. Then, the optimal strategy would have been to place that previous ambivert at an empty table, and now once we arrive at the present moment, we'd be able to seat this new extrovert.
Of course, treating this ambivert as an introvert (to seat this extrovert and future extroverts) could mean we're unable to seat a future introvert. Fortunately, extroverts and introverts have the same weight with regards to the final answer, so this doesn't matter (plus one extrovert + minus one introvert gives the same final answer).
This approach can be implemented in $$$O(N)$$$ time. For details, see my submission.
Thanks, yes this regret greedy makes sense, unfortunate that I did not think of it tho lol.
I'm still not understanding their maintain min and max number of tables allocated solution though, I will think on it
Amazing!
I think I noticed a greedy for B. Somebody else did? Once I have it done, I will submit it :)
I solved Problem E by only observing the samples and guessing the conclusion. Is there a detailed proof?
Tutorial for problem only gives a hint about anti-diagonals, which is cool, however there is no explanation of how to calculate the answer. Solution code is quite long, but in tutorial it's covered by just:
https://codeforces.me/contest/2232/submission/376691826
can someone please expplain why this fails, the main diff is in absence of min(ans, sum/i+1) i do not get when my logic fails.
Amazing contest!
Refering to your question, I dont really know why? The logic is simmilar. The most i can guess is off-by-one errors. The logic really needs to be
sum += a; h = min(h, sum / i);andito go from1ton;its because averaging out is a wrong soln when its larger than the current height. 2 6 1 is a gud example. avg is 3, but i cannot do that, frost cannot be shifted back
can we sovle c1 by couting number of extroverts and introverts after every A using prefix approaoch
and then making good decision every time an ambivert comes
very beautiful problem D!
Also, there is another greedy approach for C2.
https://codeforces.me/contest/2232/submission/376748313
that's a shame that I submitted this in the last 30 secs and because of not getting free variable in long long i got WA on pretest 18 :)
the second one is a nice problem
can u please check out my query, i did not use min, but i am not getting how do we come to think of min, what was ur thought. i thought, if the next val if smaller than my ans, i will set the maxH to average. else i will cut to the ans i am already having.
You must use min think about 4 100000 0 100000 10000 example. While I was solving the question İ thought about a similar testcase and observed that if the min of the prefix is smaller than the average of the prefix then the answer is the min
fair, it took a few min to get the soln, 2,6,1 is a good testcase that helps to understand.maybe the bad assumtipn was that if current height is less than prevH, i gotta distribute it. i cud have extras, and the math will just distribute it backwards too, which is against the rules. averaging out works, only if its smaller than prevH. it can be larger becaue u can have extras. like in 2,6,1 i get till 2,2 but 4 is xtra, and i cannot give it to i = 0.
but man it was tricky to get this during contest, do u think about extreme testcases, is it natural to not get the complete picture initially, how did u get ahead of this prob
I guess you need to practice more to develop necessary intuitions just keep practicing
cake leveling solo leveling reference??
got WA at C2 because of $$$x \cdot s \gt 2^{31}-1$$$ and overflowed(:lmao)
Guys, can somebody figure out the problem with my code (C2 problem), I am not able to comprehend the case where this could go wrong, if anyone is interested please help find the issue and share with me. I get wrong answer on test 16 some case.
https://codeforces.me/contest/2232/submission/376771561
There is a testcase that leads to WA (found with the help of AI, which means I don't know whether it is the right one makes your code failed)
1 18 3 7 EEIAAEEAAAEIIIAAEA
expected: 14 actual: 15
Thank you, understood the issue with the help of the case.
I'm assigning Ambiverts to new tables first but the problem is if lets say one table is full, and 2 other tables have ambiverts each, I'm assuming I can replace the ambivert with an introvert by moving it to an already partially filled table, (table 2), but I never marked that the ambivert on table 3 has nowhere to go except only table 2, after moving it to table 2, I don't have a slot for next introvert. My ambiguous counter says I still have a replaceable ambivert but I don't.
https://codeforces.me/contest/2232/submission/376791142
There's an alternative nlog(n) solution to C2 using a segment tree which can be optimized to linear time. Check my submissions.
I think I found a great solution for both the C1 and C2 problems:
We make an assumption that we generally make the 'A's seat as an 'E', because the occupancy for 'E' is more in number. Thus in general, we increment cea everytime we encounter an 'A'.
Now, while traversing through the string, we only get into trouble finding a seat for 'E', if either num == 0 or if ans/n == s (All the tables are fully occupied).
In this case we check whether we previously have an 'A' that was seated like an 'E'. If yes, we simply give that 'A' a completely new table, and make 'E' sit on 'A's initial position. We also decrement nea by one in this case. Notice that since we always make 'A' seated as an 'E', we also need to check this condition whenever we encounter an 'A'
An introvert can always be seated, unless the value of num == x.
The traversing of the string can be broken once we get a value of answer which is greater than x*s, in which case we print the answer as x*s. Otherwise print the final ans after traversing the complete string. This way we can get the ans directly in a single pass in O(n) time.
This is my code for both C1 and C2 : 376854024 I was working on these lines during the contest, but sadly couldn't complete the code and hence got only 2 AC submissions in the contest :(
This is a very clever and elegant approach!
I really liked problem D, was a nice twist on tower of hanoi. But i was wondering, whats the optimal algorithm, that moves all the layers in the fewest moves. The solution was within 2^n — 1 moves but not the most optimal, it would do extra work. So a problem variation that asks for the fewest possible moves would be interesting. I thought of this, but it was very hard to solve myself. I'm very curious to find the solution.
Boy, you and I ruined the 67 comment count.
As for your question, it would probably have been much much harder. The whole idea that we could move MORE than 3 rings(max) at once was pretty complicated already and required some pretty nieche greedy tricks already.
It would probably be the same thing only that more restrictions on HOW and IN WHAT ORDER you decide to move them. I am courious how the code might look!
The algorithm mentioned is the editorial will produce the shortest possible sequence
thanks !
Can someone explain what does this mean in the solution C2 proof.
For $$$f(i)$$$, the first $$$i$$$ ambiverts are seated like they are introverted. (I just say the first $$$i$$$ ambiverts are introverted for short.)
Therefore, the difference between $$$f(i + 1)$$$ and $$$f(i + 2)$$$ is how the $$$(i + 2)$$$-th is acting (extroverted for $$$f(i + 1)$$$ and introverted for $$$f(i + 2)$$$).
In Problem C2, Found the following way to think about the diminishing returns logic more intuitive -
Let f(i) = maximum people seated when the first
iambiverts are forced to act as introverts, remaining ambiverts act as extroverts. LetT_idenote this timeline.Claim: if
f(i) > f(i-1), thenf(i-1) > f(i-2).Note that
T_iandT_{i-1}are identical up to thei-th ambivert, they only diverge there. This means just before thei-th ambivert arrives,T_{i-2}has exactly one fewer active table thanT_{i-1}.Since
f(i) > f(i-1), forcing thei-th extra table was beneficial. This means at some future pointj(post the ith Ambivert), all ofT_{i-1}'s tables are completely full. At that same point,T_{i-2}'s tables are also completely full — the same stream of people filling fewer tables fills them just as easily.So at point
j,T_{i-1}hasmfully filled tables andT_{i-2}hasm-1fully filled tables, and both face an identical remaining suffix fromjonward.From here it is obvious — one extra fully filled table with the same suffix ahead is strictly better, that is
sextra people already seated. The only escape would be if the venue hits full capacityx*s, butf(i) > f(i-1)guarantees it didn't — otherwiseT_icouldn't have improved onT_{i-1}.So the advantage is permanent. Hence
f(i-1) > f(i-2).problem E is really amazing
I found a solution with fewer steps than the standard recursive approach for problem D, but it got a wrong answer. Is there any case where a "faster" (shorter step count) solution is invalid?
C also solved binary search[submission:377858111]
why this if else is not trivial for me :(
Note: The spoiler within a spoiler seems to not work when I post the comment though it is visible in the preview. Apologies for this issue.
An important observation needed to solve this problem is the fact that in each antidiagonal, exactly $$$1$$$ new snake is added or removed while all the remaining snakes make some move. Additionally, each snake spans from the $$$i$$$th antidiagonal from the start to the $$$i$$$th antidiagonal from the end.
Another important observation is that once we are at the stage of traversing antidiagonals where all snakes are added, the rest of the cake is predetermined. Because of this, we can build our result off of only the first half of the construction.
To count the number of possible arrangements of snakes, we can color the cake in three different colors. Let's use red to represent segments of snakes given to us in the input, blue to represent segments of snakes that can transition in more than one way to the next antidiagonal, and yellow to represent segments of snakes that can only move in one direction to the next antidiagonal.
We can observe that based on the arrangement of red tiles, we can determine whether or not other tiles will be colored blue or yellow. We can use the following algorithm:
- If one of the two tiles a snake can move to from the current tile is red, color it yellow
- If a neighboring tile on the current tile's antidiagonal is yellow, color it yellow
- Otherwise, color the tile blue
Why? The first condition is true by the definition of the coloring. For the second condition, we can observe how if some snake is forced to move to a certain tile for the next antidiagonal, the free neighbors of this snake will have to move with it. This can be observed in the following illustration:
Here, irrelevant tiles are represented in grey. The green arrows show possible moves, the orange arrows show moves possible for the individual tile that are not compatible with the rest of the arrangement, and the black arrow shows a move that cannot happen. It can be clearly seen that if an orange arrow is chosen, the black arrow must be chosen as well. This causes this set of tiles to be fixed.
Now, to solve this problem, we can simply multiply the lengths of connected components of blue tiles in each antidiagonal. Why? This can be observed in the following illustration:
. As can be seen, we can choose some spot to split the pattern and make room for the new snake. There are exactly $$$m+1$$$
such splits where $$$m$$$ is the length of some blue segment for each segment. We can multiply these values to find the number of snake arrangements.Apologies for poor quality of explanation, I am very tired.
Man, The Problem B is easier than A
C1 and C2 can be solved in O(n) https://codeforces.me/contest/2232/submission/385501118