Thank you for participating! I hope you enjoyed the problems.
2233A - AI Project Development
Idea: FelixArg
Tutorial
Tutorial is loading...
Solution (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int int_ceil(int x, int d){
return (x + d - 1) / d;
}
void solve(){
int n, x, y, t;
cin >> n >> x >> y >> t;
int ans = int_ceil(n, x + y);
if (t * x <= n){
ans = min(ans, int_ceil(n - t * x, x + 10 * y) + t);
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Idea: FelixArg
Tutorial
Tutorial is loading...
Solution 1 (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
if (n % 2 == 0){
for (int i = 0; i < n; i += 2){
cout << (i + 2) << ' ' << (i + 1) << ' ' << (i + 1) << ' ' << (i + 2) << ' ';
cout << (i + 1) << ' ' << (i + 2) << ' ' << (i + 2) << ' ' << (i + 1) << ' ';
}
}
else{
cout << "3 3 2 1 1 2 1 2 2 3 1 3 ";
for (int i = 3; i < n; i += 2){
cout << (i + 2) << ' ' << (i + 1) << ' ' << (i + 1) << ' ' << (i + 2) << ' ';
cout << (i + 1) << ' ' << (i + 2) << ' ' << (i + 2) << ' ' << (i + 1) << ' ';
}
}
cout << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Solution 2 (FelixArg)
#include<bits/stdc++.h>
using namespace std;
mt19937 rng(chrono::high_resolution_clock().now().time_since_epoch().count());
#define int long long
bool check(vector<int> &a){
int n = a.size() / 4;
vector<vector<int>> p(n);
for (int i = 0; i < 4 * n; i++){
p[a[i]].push_back(i);
}
for (int i = 0; i < n; i++){
if (p[i].size() != 4){
return false;
}
if (p[i][1] - p[i][0] == p[i][2] - p[i][1] ||
p[i][3] - p[i][2] == p[i][2] - p[i][1] ||
p[i][3] - p[i][2] == p[i][1] - p[i][0]){
return false;
}
}
return true;
}
void solve(){
int n;
cin >> n;
vector<int> a;
for (int i = 0; i < n; i++){
for (int j = 0; j < 4; j++){
a.push_back(i);
}
}
while(!check(a)){
shuffle(a.begin(), a.end(), rng);
}
for (int x : a){
cout << x + 1 << ' ';
}
cout << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2233C - Cost of a Bracket Sequence
Idea: BledDest
Tutorial
Tutorial is loading...
Solution 1 (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1000000007;
void solve(){
int n, k;
cin >> n >> k;
string s;
cin >> s;
int val_ans = INF;
string ans(n, '0');
for (int i = 0; i <= n; i++){
string t = s;
string cur_ans(n, '0');
int cur_k = k;
for (int j = 0; j < i; j++){
if (t[j] == '(' && cur_k > 0){
cur_ans[j] = '1';
t[j] = ')';
cur_k--;
}
}
for (int j = n - 1; j > i; j--){
if (t[j] == ')' && cur_k > 0){
cur_ans[j] = '1';
t[j] = '(';
cur_k--;
}
}
int val_cur = 0;
int bal = 0;
for (int j = 0; j < n; j++){
if (bal > 0 && t[j] == ')'){
val_cur += 2;
bal--;
}
else if (t[j] == '('){
bal++;
}
}
if (val_ans > val_cur){
val_ans = val_cur;
ans = cur_ans;
}
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Solution 2 (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1000000007;
void solve(){
int n, k;
cin >> n >> k;
string s;
cin >> s;
vector<int> pref_open(n + 1);
vector<int> pref_close(n + 1);
for (int i = 0; i < n; i++){
pref_open[i + 1] = pref_open[i] + (s[i] == '(');
pref_close[i + 1] = pref_close[i] + (s[i] == ')');
}
int total_close = pref_close[n];
int pos = n;
for (int i = 0; i < n; i++){
if (pref_open[i] + total_close - pref_close[i] <
pref_open[pos] + total_close - pref_close[pos]){
pos = i;
}
}
string ans(n, '0');
for (int i = 0; i < pos; i++){
if (k > 0 && s[i] == '('){
ans[i] = '1';
k--;
}
}
for (int i = pos; i < n; i++){
if (k > 0 && s[i] == ')'){
ans[i] = '1';
k--;
}
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Idea: FelixArg
Tutorial
Tutorial is loading...
Solution (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++){
cin >> a[i];
}
auto b = a;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
for (int i = 0; i < n; i++){
a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
}
vector<vector<int>> blocks(n);
vector<int> cntb(n);
for (int i = 0; i < n; ){
int j = i;
while(i < n && a[i] == a[j]){
i++;
}
blocks[a[j]].push_back(i);
blocks[a[j]].push_back(i - 1);
blocks[a[j]].push_back(j);
blocks[a[j]].push_back(j - 1);
cntb[a[j]]++;
}
auto check = [&](int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= n){
return 0;
}
swap(a[x], a[y]);
vector<int> cnt(n);
for (int i = 0; i < n;){
int j = i;
while(i < n && a[i] == a[j]){
i++;
}
cnt[a[j]]++;
}
swap(a[x], a[y]);
for (int i = 0; i < n; i++){
if (cnt[i] > 1){
return 0;
}
}
return 1;
};
for (int i = 0; i < n; i++){
if (cntb[i] > 1){
if (cntb[i] > 3){
cout << "NO\n";
return;
}
bool ok = 0;
sort(blocks[i].begin(), blocks[i].end());
blocks[i].erase(unique(blocks[i].begin(), blocks[i].end()), blocks[i].end());
for (int x : blocks[i]){
for (int y : blocks[i]){
if (x < y){
ok |= check(x, y);
}
}
}
if (!ok){
cout << "NO\n";
return;
}
break;
}
}
cout << "YES\n";
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2233E1 - Permutation Transmission (Easy Version)
2233E2 - Permutation Transmission (Difficult Version)
Idea: FelixArg
Tutorial
Tutorial is loading...
Solution E1 (FairyWinx)
#include <bits/stdc++.h>
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define len(a) (int)(a.size())
#ifdef LOCAL
#define __lg(n) log2(n)
#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using int128 = __int128;
template<typename T>
using PQ = priority_queue<T, vector<T>, greater<>>;
const int N = (1 << 18);
void solve() {
int n;
cin >> n;
vector<int> p(n);
iota(all(p), 1);
int k = 0;
while ((1 << (k)) <= n) ++k;
vector<string> s(n);
for (int i = 0; i < k; ++i) cin >> s[i];
map<string, int> used;
int pp = 1;
for (int i = 0; i < k; ++i) pp *= 3;
for (int i = 0; i < n; ++i) {
string z;
for (int j = 0; j < k; ++j) z += s[j][i];
if (*max_element(all(z)) == '0') {
cout << 0 << '\n';
return;
}
if (used[z]) {
cout << 0 << '\n';
return;
}
used[z] = 1;
}
vector<bitset<N>> cum(k);
for (int i = 0; i < k; ++i) {
for (int j = 0; j < n; ++j) {
cum[i][j] = bool(s[i][j] - '0');
}
}
vector<bitset<N>> ed((1 << k));
ed[0].set();
for (int mask = 0; mask < (1 << k); ++mask) {
for (int i = 0; i < k; ++i) {
if ((1 << i) & mask) {
ed[mask] = ed[mask - (1 << i)] & cum[i];
break;
}
}
}
auto get_mask = [&](int mask1, int mask2) -> int {
int res = 0;
int pw = 1;
for (int i = 0; i < k; ++i) {
if (mask2 & (1 << i)) {
res += 2 * pw;
} else if (mask1 & (1 << i)) {
res += pw;
}
pw *= 3;
}
return res;
};
auto from_mask = [&](int val) -> pair<int, int> {
int pw = 1;
for (int i = 0; i < k - 1; ++i) {
pw *= 3;
}
int mask1 = 0, mask2 = 0;
for (int i = k - 1; i >= 0; --i) {
int ost = val % pw;
int tmp = val / pw;
val = ost;
if (tmp == 2) {
mask1 += (1 << i), mask2 += (1 << i);
} else if (tmp == 1) {
mask1 += (1 << i);
}
pw /= 3;
}
return {mask1, mask2};
};
vector<ll> dp(pp, 0);
dp[0] = 1;
ll ans = 0;
for (int mask = 0; mask < pp; ++mask) {
if (dp[mask] == 0) continue;
auto gd = from_mask(mask);
int mask1 = gd.first, mask2 = gd.second;
int cnt = 0;
for (int i = 0; i < k; ++i) {
if (mask1 & (1 << i)) {
++cnt;
}
}
if (cnt == k) {
ans += dp[mask];
continue;
}
int deg = k - 1 - cnt;
if (n & (1 << deg)) {
for (int i = 0; i < k; ++i) {
if ((1 << i) & mask1) continue;
auto mask_res = get_mask(mask1 + (1 << i), mask2 + (1 << i));
dp[mask_res] += dp[mask];
}
} else {
for (int i = 0; i < k; ++i) {
if ((1 << i) & mask1) continue;
auto tmp_bit = ed[mask2] & cum[i];
if (dp[mask] != 0 && tmp_bit.none()) {
dp[get_mask(mask1 + (1 << i), mask2)] += dp[mask];
}
}
}
}
cout << ans << '\n';
}
signed main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
}
Solution E2 (FelixArg)
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
int k = 1;
while((1 << k) <= n){
k++;
}
vector<string> s(k);
for (int i = 0; i < k; i++){
cin >> s[i];
}
vector<pair<int, int>> ord(k, {0ll, 0ll});
for (int i = 0; i < k; i++){
auto& [x, ind] = ord[i];
ind = i;
for (int j = 0; j < n; j++){
x += (s[i][j] == '1');
}
}
sort(ord.rbegin(), ord.rend());
vector<int> fact(k + 1);
fact[0] = 1;
for (int i = 1; i <= k; i++){
fact[i] = fact[i - 1] * i;
}
vector<int> p(n);
for (int i = 0; i < n; i++){
for (int j = 0; j < k; j++){
int bit = s[ord[j].second][i] - '0';
p[i] ^= (bit << j);
}
}
sort(p.begin(), p.end());
if (p[0] != 1){
cout << 0 << '\n';
return;
}
for (int i = 1; i < n; i++){
if (p[i] != p[i - 1] + 1){
cout << 0 << '\n';
return;
}
}
vector<int> cnt(n + 1);
for (auto [x, ind] : ord){
cnt[x]++;
}
int ans = 1;
for (int i = 0; i <= n; i++){
ans *= fact[cnt[i]];
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Idea: FelixArg
Tutorial
Tutorial is loading...
Solution (FelixArg)
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int INF = 1000000007;
void solve(){
int n, a, b;
cin >> n >> a >> b;
int g = gcd(a, b);
a /= g;
b /= g;
vector<int> d1, d2;
for (int i = 1; i * i <= a; i++){
if (a % i == 0){
d1.push_back(i);
if (i * i != a){
d1.push_back(a / i);
}
}
}
for (int i = 1; i * i <= b; i++){
if (b % i == 0){
d2.push_back(i);
if (i * i != b){
d2.push_back(b / i);
}
}
}
sort(d1.begin(), d1.end());
sort(d2.begin(), d2.end());
int sz1 = d1.size();
int sz2 = d2.size();
vector<vector<int>> to_d1(sz1, vector<int> (sz1, -1));
for (int i = 0; i < sz1; i++){
int u = 0;
for (int j = i; j >= 0; j--){
while(u < i && d1[i] > d1[u] * d1[j]){
u++;
}
if (d1[i] % d1[j] == 0 && d1[i] / d1[j] == d1[u]){
to_d1[i][j] = u;
}
}
}
vector<vector<int>> to_d2(sz2, vector<int> (sz2, -1));
for (int i = 0; i < sz2; i++){
int u = 0;
for (int j = i; j >= 0; j--){
while(u < i && d2[i] > d2[u] * d2[j]){
u++;
}
if (d2[i] % d2[j] == 0 && d2[i] / d2[j] == d2[u]){
to_d2[i][j] = u;
}
}
}
vector<vector<int>> dels_d1(sz1);
for (int i = 0; i < sz1; i++){
for (int j = 0; j <= i; j++){
if (d1[i] % d1[j] == 0){
dels_d1[i].emplace_back(j);
}
}
}
vector<vector<int>> dels_d2(sz2);
for (int i = 0; i < sz2; i++){
for (int j = 0; j <= i; j++){
if (d2[i] % d2[j] == 0){
dels_d2[i].emplace_back(j);
}
}
}
vector<vector<int>> dp(sz1, vector<int> (sz2, -1));
auto go = [&](auto&& self, int x, int y) -> int{
if (dp[x][y] != -1){
return dp[x][y];
}
if (x == 0 && y == 0){
return 0;
}
dp[x][y] = INF;
for (int dx : dels_d1[x]){
for (int dy : dels_d2[y]){
if (dx == 0 && dy == 0){
continue;
}
dp[x][y] = min(dp[x][y], max(d1[dx], d2[dy]) + self(self, to_d1[x][dx], to_d2[y][dy]));
}
}
return dp[x][y];
};
cout << go(go, sz1 - 1, sz2 - 1) << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
//cin >> tests;
while(tests--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}








Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).
Here's my construction, which doesn't require separate handling for odd and even $$$n$$$:
Yea, yours looks much better. Thank you so much!
mine is a little complicated... ~~~~~~
include<bits/stdc++.h>
define ll long long
using namespace std;
int main(){ int t;cin>>t; while(t--){ int n;cin>>n;
vector<int> A; if(n==2){ cout << "1 2 1 2 2 1 1 2\n"; continue; } for(int i=1;i<=n;++i){ A.push_back(i); A.push_back(i); } if(n&1){ for (int i = 1; i < n; i += 2) { A.push_back(i); A.push_back(i+1); A.push_back(i); A.push_back(i+1); } A.push_back(n); A.push_back(n); swap(A[A.size()-2],A[A.size()-3]); } else{ for(int i=1;i<=n;i+=2){ A.push_back(i); A.push_back(i+1); A.push_back(i); A.push_back(i+1); } } for(auto &i:A)cout << i << ' '; cout << '\n'; cout << '\n'; }} ~~~~~~
Beautiful construction.
waw frr u ve done a brilliant job with this :)
Well Here is mine, without any cases either, though this is a terrible solution but yet kinda unique am I right or am I right? 377940813
heck this solution is so cool! T_T
here is mine
mine also doesn't require case work
You know the answer for n = 2 is {1,2,1,1,2,2,1,2}
Now if you know the answer for n = k you can get the answer for n = k+1 just by writing one k+1 just after every k
Interesting, thank you :)
You can also random shuffle. 377929631
Hmm, I'm not very familiar with this kind of solution. Thank you so much :)
This also works:
a = [1,2,...,n,1,1,2,2,...,n,n,1,2,...,n] if(n%2){ swap(a[0], a[n/2]) } print(a)
Nice one. Seems like there are a lot of possible solutions for this problem. Thank you!
Handled cheaters very well :>
How?
377959479
did anyone do B like this?
mine is slightly different (in the 3rd step) Yours is much cleaner
377956798
kudos
Holy smokes E is beautiful but also I have no idea how I could have seen that myself :(
Its me or C was too hard??
+1
C is standard difficulty for a div2C, 1400 is not too hard at all
I didn't have much trouble with it, the hardest part for me was solving the subproblem of finding the longest RBS substring (not required, but I used it in my solution)
Is this right for F? It took me about an hour on D and I couldn't submit my code of F in time at last because the page got stuck while loading :(
I don't know if I'm right, but another construction that works for B is: a b a b b a a b
Where distances from a, are:
2, 3, 1
And from b:
2, 1, 3
And maybe you have more settings if you figure out to swap the orders by keeping the "coherence" between the two interlinked distances. I'm not sure about that, though.
got this solution for B by mistake
i got the same solution lol
;)
I have a question for the editorial of F.
So basically I have an extra observation, which is in the transition, only one of a and b, can have multiple prime factors removed/added to it (i.e. the other one must have <=1 prime factor added/removed).
Proof: Assume that the optimal path consists of a single process which removes multiple prime factors from a, and adds multiple prime factors to b (what I mean by multiple here is >=2). Then, assume that the removed factors have a product of A and those added have a product of B. Also, let i<=j,k<=l be positive integers >=2, such that ij=A, kl=B. This is always doable as we remove multiple prime factors at the same time. Let's say we pair up (i,k), (j,l). If i<=k and j<=l, then the cost of doing operation (i,k) then (j,l) = k+l, the original cost is kl, which must be >= k+l. Same works if i>=k and j>=l.
Now, WLOG, assume that i<=k<=l<=j. If A>=B, the original cost is ij, the new cost can be constructed to be k+j <= 2j <= ij. If A<B, the original cost is kl, the new cost is k+j. Since ij<kl, j<kl/2. So new cost < k+kl/2 <= kl. Hence, if multiple prime factors are removed from a, and multiple added to b, we can always proof that there exists a better or equally good solution, by doing the above adjustment.
When doing the transition, as a result, I believe that we only need to enumerate the prime factors on a, with factors on b, and the prime factors on b, with factors on a. Does this transition work better in this problem?
As a side note, even when enumerating the prime factors p on one side, with the factors on the other side, we actually don't need to enumerate any factors F, such that there exists some g that is a factor of F, where F/g>p.
This is exactly my solve orz
My solution for B was
If n is even then: 1, 1, 2, 2, 3, 3, ..., n-1, n -1, n, n, 1, 2, 1, 2, 3, 4, 3, 4, ..., n-1, n, n-1, n
Else if n is odd then: n, 1, 1, 2, 2, 3, 3, ..., n-1, n-1, n, n, 1, 2, 1, 2, 3, 4, 3, 4, ..., n-2, n-1, n-2, n-1, n
But this dont work for n = 2 so i checked if n == 2 then output 1, 2, 1, 1, 2, 2, 1, 2
What I did for B was simple :
n, 1, 1, 2, 2 ... n-1, n-1, n, n, 1, 2, 3, ...n-1, n, 1, 2, 3, ... n-1Worked like a charm!
PS: Dont hack me :(
I was only able to solve A and B
can someone explain me how to actually think for C problem
What is did was, assign a score for every bracket , for opening — count number of closing brackets after it. And for closing — count number of opening bracket before it. Just remove the one with with the highest count. Repeat the steps k time.
I hate horrible implement of D.
I don't think it was horrible.
My way of doing it was:
In D There is no need to prove that u can say NO if number of problematic index is >4 U can take a big number like 1000 and solution will still pass eg:
https://codeforces.me/contest/2233/submission/378004270
My goat lazypanda actually did binary search on it and found the constant 3350 to TLE :)
I have done problem C using Graphs. Lets represent each bracket as a node and draw undirected edge between '(' and ')'. It is always good to remove the node with max degree. By doing it k times we find the answer.
hmm
I thought about the same now I tried to do the contest in a Virtual Participation. The Graph is kind of weird, but you can match the first '(' you find with the first right ')'. Now, if you find a ')' before matching it, it means that it will sum one to the degree of the first '('.
However, as I could not do that logic by myself as I thought it was kind of incomplete, I just gave up and came to the editorial and tried to implement the idea myself.
Do you have the submission so I can check if I thought the same?
I rewrite my code 4 times for D :sob:
Took me like 2 hours after the contest to upsolve D. Holy orz
Another construction for B: Hardcode for n= 2,3 Rest of cases: Identity permutation, Identity permutation, Shifted identity permutation to the right, Shifted identity permutation to the left.
There is another way of showing the claim of E2 (also solve the whole problem):
For any positive integer sequence $$$A$$$ of length $$$N$$$ without duplicate, $$$A$$$ would be a permutation of $$$[1, 2, \ldots, N]$$$ if and only if $$$\sum\limits_{i = 1}^N A_i = \frac{N(N+1)}{2}$$$.
So the problem is reduced to finding the number of ways to permute strings so the sum is $$$\frac{N(N+1)}{2}$$$. Since this is the lower bound of the sum over any positive integer sequence without duplicate, we can relax the condition into minimize the sum and check if it is $$$\frac{N(N+1)}{2}$$$.
The only way to minimize it is to sort strings by frequency of $$$1$$$ bits. Which deduce the final solution in the editorial and also prove why we can permute strings with same number of $$$1$$$ bits arbitrarily.
This is a beautiful idea, thank you! I kinda even wish we thought about this approach and used it in editorial instead of our solution method.
thanks! really nice.
377950426
My soln for B was eg. n = 3
"1 2 3" "1 2 3" "2 3 1" <-- (rotate by 1) "1 2 3"
My solution to B: Start with n=2 case, For n>2 — append all numbers 3...n to the right of each 1.
With a careful implementation, I solved F 378020300 using Dijkstra’s algorithm in $$$O(d(ab)^2)$$$.
Can it be hacked?
I thought C was DP? was anyone able to define a DP state which works in O(n^2)
https://codeforces.me/contest/2233/submission/377995365
I basically tried constructing something like ))))(((( and used dp to find the optimal split by taking min of ( on left and ) on right but state is O(n)
Unfortunately I missed some of the cool observations for E2 and overkilled, my solution is follows:
Submission: 377991037
Idea:
First lets fix the top string, (0000...1111) we need to verify that the count of 0s, is correct here.
Since any rearrangement of other strings would automatically handle (0000) guys, now the problem reduces to rearrangining the remaining strings such that those starting at (1111) are correctly handled. Similary to traversing a binary trie top down.
Hey !! Saw your solution for E1 posted in editorial cmmts sections for last edu 191 contest can you elaborate how the idea came i mean there would have been a series of thoughts questions you asked yourself and also can you elaborate your solution a bit more i mean if you are free Thankss!!!!
This is some text.
an interesting one
In D, checking if the array is arranged correctly after a swap can be done in constant time
In the $$$O(n)$$$ editorial solution for problem C:
A closing bracket remains unmatched only if, at the moment it is processed, there were more closing brackets than opening brackets before it.
However, for a string such as
)))(), the 5th character gets matched although there are more closing brackets that opening brackets proceeding it. I think what is true, instead, is that a closing bracket at index $$$i$$$ is not matched iffWe can then use that to prove that the total number of unmatched closing brackets is:
For each good type, consider its maximum and minimum index at which it appears. If the inclusive difference between this max and min is equal to the # of goods of that type in the array this good type is fine. Otherwise it will need an operation to fix it. If there are 0 good types that need to be fixed, then we don't even need to do anything
Observation: A swap only changes the maximum and minimum index for the good types involved in this operation. Since a swap occurs between 2 indices, only 2 good types can have their maxis and minis updated. Thus if there are more than 2 good types that need to be fixed, it is impossible.
If there's 1 or 2 good types to fix, then consider one(the first) of those good types (potentially the only one that needs to be fixed, which in that case it encompasses other good types that work). We know an operation must include either that good type's maxi or mini since otherwise it's maxi-mini+1 value wouldn't change and we could never find a way to make that quantity equal to the total # of instances of that good type. Then bruteforce swap every other position in the array with either the maxi position of that particular good type or the mini position of that particular good type. If even one of these swaps works then we're good
Kinda clunky but to see if a swap works with a given index keep a map of sets of all the indices for every good type (the key of the map). Then between the given index and every other index in the array we can easily simulate a swap by adding and deleting indices in the appropriate sets and then check to see if the problem good types (stored in another set) are fixed (as well as making sure we didn't screw up the maxi-mini+1 range of the value of the index chosen by brute forcing over the array). If we find something that works then awesome. Just make sure you aren't swapping an index with itself or an index with another index that are of the same good type since that doesn't even do anything (it breaks the way sets work since sets can't store multiple of the same value).
What's the definition of pref_open and suff_close in C? I didn't really understand.
I understand it now after reading the code. ╰(*°▽°*)╯
During the open hacking phase, all non-mine submissions show
Source: N/A, and clickingCopyalso givesN/A. I can view my own submissions normally. I also tested old problem submissions, recent contest submissions, and different users. Same result: other users’ source is alwaysN/A. The announcement says we should have access to copy any solution during the 12-hour hacking phase.why question F is so vague and unclear ??
tried B for almost 1.5 hour after solving A, wasted 3 pages of my notebook to get an idea, failed horribly, how can i improve in these kinds of problems?
These are called Construction Problems. They can often get 'if you see it, you see it'. But with practice, we can learn their pattern. Like this one was more approachable. The key observation was that we only have to solve this problem for n=2 and n=3, then we can extend this solution to any n. This comes with enough practice. To consistently solve Div2-B, I would suggest you solve problems between 1000 — 1200 rating.
the shuffle method in B is really interesting — but how are we sure that it works within the given time limit? does there exist a way to calculate the time complexity of functions like these, averaged over a long number of trials, for example?
also, are all permutations generated by shuffle equally likely? how would the time taken change in case the function is biased towards certain permutations? sorry if the questions seem very noob
For problem B this worked for me. but no exact idea why. initially i was thinking of rotating by 1, then by n-1 but that didn't work so i thought may be rotate them by increasing value might work. but no idea how this actually works for all cases. how to prove that this will work always?
What is the rating system in educational rounds , why rating is not updated yet.
are ratings not updated yet??
Educational Codeforces Round 191 (Rated for Div. 2)
Straightforward solution for C
(The ones in the comments look daunting for newbies like me)
E is beautiful.
for C, can sb tell me where im wrong?
we map +1 to '(' and -1 to ')' and keep a prefix sum, now let e be, the last value of the prefix sum, and m be. the minimum value of the prefixes
now its obvious that max(e, 0) is the number of unmatched '('.
and we can say that the number of unmatched ')' is m because when we hit the minimum its obvious that we have atleast m, ')' unmatched on that prefix and therefor in the whole array, and if at any point there could be more unmatched, m would be lower, so could we say:
cost = n — |min(m, 0)| — max(e, 0)
now we can say that removing a '(' before m decreases both which in the end haas no effect and just wastes k. same reasoning for ')'.
so we try to remove as many ')' as possible, after m. my sol(WA'ed): 377987973
my reasoning seems logical but fails miserably in practice, and could i fix it somehow
Now that open hacking is over, I'll post my alternate solutions since I had an irrational fear of getting hacked
For A I used binary search because I was too lazy to derive the formula for using AI lol: 377924003
Now here's my alternate solution for C:
We will repeatedly delete the leftmost or rightmost bracket from the longest RBS substring $$$k$$$ times. To decide which bracket to delete, if there is a left bracket to the left of the leftmost bracket in the RBS, we will delete the right bracket, since it would create an RBS of the same size, otherwise we will delete the left bracket. The longest RBS substring can be found in $$$O(n)$$$, but it's somewhat difficult to explain so look at my AC code if you need it. Also, we will break early if there is no RBS substring.
Since finding the longest RBS substring takes $$$O(n)$$$, and we look for it $$$k$$$ times, the solution runs in $$$O(nk)$$$ time complexity. The proof is by "yeah that checks out".
C++ implementation: 377983530
number of transition in F can be further reduced to around $$$10^7$$$ by observing either $$$p$$$ or $$$q$$$ is prime in optimal choices, since if
holds, then
So any pairing of two composite number can be decomposed into two "smaller" pairing without worsening the cost.
I hate this. Solution submitted with PyPy got hacked, but the same solution submitted with Python3 passes all tests.
i have a better solution for problem b: ~~~~~ void solve() { int n;cin>>n; vectora(4*n); if(n==2){ cout<<2 <<" "<< 1<<" "<< 1<<" " <<2<<" "<< 1<<" "<< 2<<" " <<2 << " "<<1<<endl; return; } int start=0; int m=4*n; int x=1; while(m && x<=n){ a[start]=x; a[start+1]=x; a[start+3]=x;
if(m==4) a[2]=x; else a[start+ 6 ]=x; x++; m=m-4; start=start+4; } for(auto i:a){ cout<<i<<" "; } cout<<endl; return;}
signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);
int t; cin >> t; while (t--) { solve(); } return 0;}
~~~~~
Can somebody help in Problem C, my logic for it:
I made a binary string using the bracket sequence given and counted the '(' which contributes to the cost and gave it 1 in string, and all others are 0,
then, by looking at this cost string, I choose the k characters from this, because only these characters will lower the cost,
and make an ans string from this cost string as: 378013633 but this comes out wrong,
Please correct me and how to solve C
The cost is not only dependent on '('.
Consider the string "(((((((()" Although there are many '(', only one of them contributes to the cost.
Additionally, in this case, removing the ')' character is the most efficient way to reduce the cost. Therefore, lowering the cost may require removing both types of characters.
In my code, has considered this type of case and specifically counted these '(' for ex: (()()(()) will have the cost string of 010101100, because first '(' is not pairing up.
so according to suggestion, I should focus on removing these ')' instead of '('?
Due to the nature of the problem, you cannot focus on only one type of bracket. You may have to remove '(', and you may also have to remove ')'
I did this on b: ~~~~~ rep(i,1,n+1) cout<<i<<' '; rep(i,1,n+1) cout<<i<<' '<<i<<' '; rep(i,1,n) cout<<n-i<<' '; cout<<n; ~~~~~
a very easy construction for B:
Comparing intial array with its single (left/right) shifted array , we get to know that every elements differ by 1 from their intial position
Okay so I did not figure out any of the methods for B, got stuck on B itself, but then found a random pattern that will always satisfy the property given in the problem. The pattern is as follows : 1 2 3 ... n | 2 3 4 ... n 1 | 2 3 4 ... n 1 | 1 2 3 ... n I added the divisions in the sequence for a better clarity in reading, and we can generalize the values of difference in positions for all the numbers, viz. equal to n-1, n and n+1 for i = 2 to n, and 2n-1, n, and 1 for i = 1.
The recursive method to solve this problem is something that should've struck me during the contest, but yeah next time.
Edit : I found a better method to logically get this pattern. Basically [1, 2, 2, 1, 2, 1, 1, 2] is a valid sequence for n = 2, and now we can observe for this that to go from size n to n+1 we simply add the new elements just after the previous largest elements. The properties remain valid as the largest differences grow at the greatest rate and thus the differences can never become equal.
I ended up solving C using a different O(n) greedy based on directly destroying matched pairs and maintaining active bracket structure rather than the pref_open + suff_close observation from the editorial.
I wrote up the idea here if anyone is interested:
https://codeforces.me/blog/entry/154439
378240026
I forgot that I registered for this contest, what a pity...
However, I've found a solution for B without the need to consider the parity of n.
guys i am unable to solve the problem d can anyone explain clearly . i have asked ai to explain but its sloppy explanation made my brain rot
It was harder than usual edu div2. But got 3 done anyhow
I completely missed the construction strategy for problem B, but it turns out that backtracking, albeit an overkill approach for this problem, works in the allotted time constraint. It helps that early placements of integers never fails and each placement can be validated in constant time before recursing.
Here is my solution: 379937279
An Intuitive Explanation: Thinking with the Balance Graph (2233C — Cost of a Bracket Sequence)
Instead of staring at algebraic formulas, let us visualize the string as a trajectory on a 2D plane:
Here is the beautiful geometric insight that makes the O(n) solution trivial:
1. Why the Global Minimum (mn) represents Unmatched ')' When we scan from left to right, whenever the graph dips below its previous minimum, it means we have encountered more ')' than '(' can safely shield. Any '(' that appears AFTER a dip cannot save the ')' before it, because brackets can only match forward. Therefore, the global minimum (the lowest valley) represents the absolute bottleneck: the total number of inherently unmatched ')' in the string is exactly -mn. Since every unmatched ')' directly kills one potential pair, the maximum number of pairs we can ever form is bounded by: Max Pairs = total_close + mn.
2. The Magic Split Point (pos) Let 'pos' be the index where the graph hits this global minimum. By definition, 'pos' must be a ')' character. If we cut the string at 'pos', look at what happens to the two sides:
3. How to Minimize Pairs with k Deletions Our goal is to minimize the final cost (max pairs), which means we want to maximize the number of unmatched brackets.
This completely validates the greedy choice of 'pos' and the deletion strategy!
Very nice logic.
Thanks for the kind words! Feel free to upvote if it was helpful, it helps more people see the solution.
https://codeforces.me/contest/2233/submission/381280759-- My solution for C
An Intuitive Way to Look at the Problem
When I first looked at this problem, I couldn't really think about stack matching or prefix balances. Instead, I tried to understand how a balanced bracket sequence is actually formed.
Step 1: Looking at a single Regular Bracket Sequence
Consider any single Regular Bracket Sequence (RBS). If we scan it from left to right, there may be moments where we have seen more ) than (. These are the places where some closing brackets are temporarily “waiting” for opening brackets.
Similarly, if we scan from right to left, there may be moments where we have seen more ( than ). These opening brackets.
The important realization is this: A single RBS can only have its imbalance coming from one direction. It cannot simultaneously have unmatched ) on the right and unmatched ( on the left.
Why? Because if both kinds of unmatched brackets existed inside the same RBS, they would eventually match each other, meaning they were never truly unmatched in the first place.
So every RBS is either * right-heavy (extra ) while scanning left to right), or * left-heavy (extra ( while scanning right to left), but never both.
Step 2: What happens when multiple RBSs are placed together? Now imagine the entire string consists of several RBSs placed one after another. Suppose the first RBS is right-heavy. Then the next RBS can again be right-heavy.
Eventually, we encounter the first left-heavy RBS. Now comes the key observation: After the first left-heavy component appears, every RBS after it must also be left-heavy.
Why? Assume the opposite. Suppose after a left-heavy RBS, another right-heavy RBS appears.
The unmatched opening brackets from the left-heavy component and the unmatched closing brackets from the later right-heavy component would meet and form pairs. That means those two parts were actually connected and should have been considered one larger RBS instead of two separate ones.
This is a contradiction.
Therefore, the sequence of components looks like
Right-heavy Right-heavy Right-heavy ... Left-heavy Left-heavy Left-heavy
There can be only one transition from right-heavy to left-heavy. OR simply all being either Right-heavy only or Left-heavy only and no transition.
Step 3: Finding the transition
Now the implementation becomes straightforward. Left to Right Scan Maintain the balance. Whenever the balance becomes negative, record that index.
The last such position is stored as lastRightBracket This marks the end of the right-heavy region.
Right to Left Scan Again maintain the balance, but in reverse. Whenever the reverse balance becomes negative, record that index.
The last recorded position becomes lastLeftBracket This marks where the left-heavy region begins.
Step 4: Constructing the answer
Now the string naturally divides into three regions.
|---- Right-heavy ----|---- Middle ----|---- Left-heavy ----| 0 lastRight lastLeft n-1
Now simply choose brackets greedily.
Everything else is ignored.
This directly constructs the required answer.
Complexity
Both scans are linear.
Overall complexity:
Final Thoughts
What I like most about this solution is that it didn’t come from memorizing a known trick or an algo.
Instead, it came from asking a simple question: “Where does the imbalance of each regular bracket sequence actually come from?”
Once I realized that every balanced component can only be imbalanced from one side, the existence of a single transition point became almost obvious.
From there, the implementation naturally followed with just two linear scans.