BledDest's blog

By BledDest, 13 hours ago, In English

2283A - Numbers on the Board

Tutorial
Solution

2283B - Rhythmic String

Tutorial
Solution

2283C - Big XOR

Tutorial
Solution

2283D - Black, Gray and White

Tutorial
Solution (awoo)

2283E - Partition of a Binary String

Tutorial
Solution

2283F - Minimize the Graph

Tutorial
Solution

2283G - Order Statistics on the Graph

Tutorial
Solution
  • Vote: I like it
  • +23
  • Vote: I do not like it

»
13 hours ago, hide # |
← Rev. 4  
Vote: I like it 0 Vote: I do not like it

G can be solved with simple brute force over all 2^N masks + binary lifting lol

Code

and an alternative approach for C would be, we just need to choose which numbers from 1 to N to double so that the XOR of the resulting array is at least twice the bitwise OR of the original array

The key observation is that we only need to double powers of two. Their effects on the XOR allow us to construct the exact target value

Code
  • »
    »
    6 hours ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    The brute force in-question,

    Although main thing is that even though binary lifting was one of the intended solutions actually passing it under the time contraint is difficult.

»
13 hours ago, hide # |
 
Vote: I like it +3 Vote: I do not like it

thanks for the solutions sir!

»
13 hours ago, hide # |
 
Vote: I like it +3 Vote: I do not like it

F can be solved just using lazy segment trees 397403664.

»
12 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

I had nearly an identical solution to E in my head lmao.

»
9 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Combination of 2 distinct dps on E was amazing!

»
8 hours ago, hide # |
← Rev. 2  
Vote: I like it 0 Vote: I do not like it

Hello! My approach for problem C was as follows:

First, calculate 2 * OR of all elements. We now need to set the MSB (Most Significant Bit) in our XOR, which is present in 2 * OR. We also know that if the previous MSB of the OR was at position (x), it will now be at (x + 1) (since multiplying by 2 left-shifts all set bits). Therefore, we can double the (N)-th element since it has the largest MSB, left-shifting it sets the MSB of 2 * OR in our XOR. Let (X = 2 * OR). We iterate from the highest bits downward. If a bit is set in (X) but not in our XOR, then obv we have will try to Set it cuz even if we set all the smaller bits still X will be > Since Sum of all bits from 0..i (2 ^ 0 + 2 ^ 1.. 2 ^ i < 2 ^ (i + 1) )Doubling an element equal to 1LL << (i — 1) (2 ^ (i — 1)) left-shifts its bit, which sets that bit in our XOR, so we update the XOR accordingly.

Here is my solution: 397390036

Code:

The main reason I'm posting this is to ask: is my code hackable? I mistakenly wrote Ans[N — 1] = 1 instead of Ans[N] = 1 (I accidentally mixed up 0-based and 1-based indexing) and it got AC during contest.

»
8 hours ago, hide # |
 
Vote: I like it +2 Vote: I do not like it

I have a greedy approach for Problem C.

Greedy: Process numbers from large to small

  1. Key observation The bitwise OR of all integers from 1 to n is always a number consisting entirely of consecutive 1-bits. Let L be the highest set bit of n. Then k = (1 << (L + 1)) — 1, and 2*k has all bits from position 1 to L+1 set to 1 (using 0-based indexing). Also, every chosen value is at most 2*n, so the final XOR is smaller than 2^(L+2). Therefore, we only need to make bits 1 through L+1 of the final XOR equal to 1. The result will automatically be either 2*k or 2*k+1.

  2. Greedy strategy Process i from n down to 1, maintaining tmp, the XOR of all processed elements. For each i:

  • If replacing i with 2*i makes tmp larger, choose 2*i.
  • Otherwise, keep i unchanged.

In code:

if ((tmp ^ (2 * i)) > tmp) {
    p[i] = 1;
    tmp ^= (2 * i);
} else {
    tmp ^= i;
}
  1. Why does this work? Group the numbers according to their highest set bit. For a group containing numbers in the range [2^q, 2^(q+1)-1], doubling any number in this group makes its highest set bit exactly q+1. The comparison tmp ^ (2*i) > tmp has a simple meaning:
  • If bit q+1 of tmp is 0, doubling i makes the XOR larger, so we double it and turn this bit into 1.
  • If bit q+1 is already 1, doubling i makes the XOR smaller, so we keep i unchanged. Since we process numbers in descending order, the first number in each group will set bit q+1 to 1 if necessary. All remaining numbers in that group are kept unchanged, so they cannot affect this bit. After finishing a group, its corresponding bit is guaranteed to be 1. Moreover, all numbers in subsequent groups are smaller. Neither their original values nor their doubled values can affect any previously fixed higher bit. Thus, we can greedily fix all required bits from high to low, guaranteeing that the final XOR is at least 2*k.

Implementation:

void solve() {
    int n;
    cin >> n;

    vector<int> p(n + 1, 0);
    long long tmp = 0;

    for (int i = n; i >= 1; --i) {
        long long x = 2LL * i;

        if ((tmp ^ x) > tmp) {
            p[i] = 1;
            tmp ^= x;
        } else {
            tmp ^= i;
        }
    }

    for (int i = 1; i <= n; ++i) {
        cout << p[i] << " \n"[i == n];
    }
}

Here, p[i] = 1 means choosing 2*i; otherwise, we choose i.

»
7 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Come on, people were complaining how C was harder than D. I clearly disagree, you needed to know how to binary lift and rip an LCA to solve D effectively.

For C, as long as you knew how to type ^, then you could solve C.

»
6 hours ago, hide # |
← Rev. 4  
Vote: I like it 0 Vote: I do not like it

Another implementation of C is to greedily multiply the numbers, starting with the largest.

void solve(){
	int n, ans = 0;
	cin >> n;
	vector<bool> a(n + 1);
	
	for(int i = 1; i <= n; i++) ans ^= i;

	for(int i = n; i > 0; i--) if(((ans ^ i) ^ (2 * i)) > ans) a[i] = 1, ans = (ans ^ i) ^ (2 * i);
	
	for(int i = 1; i <= n; i++) cout << a[i] << " ";
    cout << "\n";
	
}
»
6 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Wow, noticed the std for A is Python :). But I think maybe the last line print(max(0, r - l - 2 * m)) is missing a - 1 according to the tutorial formula. Is this a new anti-plagiarism feature, or just a cute little typo? ovo

  • »
    »
    4 hours ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    Whoops, I accidentally uploaded the wrong version of A. Thank you for noticing, fixed it.

»
6 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

If you are noob like me, you will make the whole xor basis first then try to maximise xorsum greedily :(

Code : 397392370

»
3 hours ago, hide # |
← Rev. 2  
Vote: I like it +3 Vote: I do not like it

Damn the editorial approach for D is so much better i used LCA + difference tree (idk the name i just wrote difference array for tree) the algo itself was simple just a lot of preprocessing the color tree thing is way more beautiful

»
3 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

are the educational rounds of codeforces is tougher than usual div 2?

»
3 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Well, I found myself forget to turn off sync_with_stdio and use endl instead of '\n', leading to two TLE of D :(

»
2 hours ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

I think this round was way too easy compared to the others. I solved 2 problems without a single failure.

»
2 hours ago, hide # |
← Rev. 2  
Vote: I like it 0 Vote: I do not like it

Solution of problem D using LCA ```````` //This is the code

include <bits/stdc++.h>

using namespace std;

void dfs(vector<vector>&up,vector<vector>&adj,vector&tin,vector&tout, int node,int p,int &timer,int l) { tin[node] = ++timer; up[node][0] = p; for (int i = 1; i <= l; ++i) { up[node][i] = up[up[node][i — 1]][i — 1]; }

for (int u : adj[node])
 {
      if (u != p)
           {
                dfs(up,adj,tin,tout,u,node,timer,l);
           }
 }

 tout[node] = ++timer;
 return;

}

bool is_ancestor(int u, int v,vector&tin,vector&tout) { return tin[u] <= tin[v] && tout[u] >= tout[v]; }

int find_lca(int u, int v,int l,vector<vector>&up,vector&tin,vector&tout) { if (is_ancestor(u, v,tin,tout)) return u; if (is_ancestor(v, u,tin,tout)) return v; for (int i = l; i >= 0; --i) { if (!is_ancestor(up[u][i], v,tin,tout)) u = up[u][i]; } return up[u][0]; }

bool fun(int total,int target,int st,vector<vector>&up,vector&tin,vector&tout,int l) { while(1) { int end=total-st; if(st>=end) { break; }

int lca=find_lca(st,end,l,up,tin,tout);

       int l1=find_lca(target,st,l,up,tin,tout),l2=find_lca(target,lca,l,up,tin,tout);
       if(l1==target&&l2==lca)
       {
           return true;
       }

       int l3=find_lca(target,end,l,up,tin,tout);
       if(l3==target&&l2==lca)
       {
           return true;
       }

       st++;
    }

    return false;

}

signed main() { int t;cin>>t; while(t--) { int n;cin>>n; vector<vector>adj(n+1); for(int i=1;i<n;i++) { int u,v;cin>>u>>v; adj[u].push_back(v); adj[v].push_back(u); }

if(n%2==0)
{
    cout<<n+1<<endl;
}
else 
{ 
    int l=ceil(log2(n));
    vector<vector<int>>up(n+1,vector<int>(l+1,0));
    vector<int>tin(n+1,0),tout(n+1,0);
    int timer=0;

    dfs(up,adj,tin,tout,1,1,timer,l);

    int st=1,a=1,st1=2;

    if(fun(n+1,(n+1)/2,st,up,tin,tout,l))
    {
      cout<<n+1<<endl;
    }
    else if(fun(n+2,a,st1,up,tin,tout,l))
    {
       cout<<n+2<<endl;
    }
    else if(fun(n,n,st,up,tin,tout,l))
    {
      cout<<n<<endl;
    }
    else 
    {
      cout<<n+1<<endl;
    }
}

}

} ```````````` // This is solution using LCA .

»
78 minutes ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

thanks for the lightning-fast editorial chef!

»
19 minutes ago, hide # |
← Rev. 2  
Vote: I like it 0 Vote: I do not like it

Problem C soln(different way) :- ****

An Elegant O(N) Approach Using Branch Labeling (Subtree Tracking)

I wanted to share my approach for this problem because I found a way to solve it optimally in O(N) time by smartly choosing tree roots and tracking which branch every node belongs to.

Here is the breakdown of the logic:

1. The Base Case (Even N) If N is even, the answer is always simply N + 1. No traversal is needed.

2. The Odd Case (Testing Candidates) If N is odd, the answer will be one of three candidates: N, N + 1, or N + 2. Instead of doing something complex, we can just test these three candidate values of K in ascending order. Since we want to update our answer if a valid state is found, looping K from N to N + 2 naturally leaves us with the highest valid candidate.

For each candidate K, we pick a very specific root to hang the tree from: * If K = N, root = N * If K = N + 1, root = (N / 2) + 1 * If K = N + 2, root = 1

3. The "Second Parent" (Branch Labeling) Technique Once we select the root for our candidate K, we need to check if there is a valid pair of nodes (i, target) where target = K — i, such that they lie in different branches connected to the root.

To do this efficiently, I used a second_parent array: * I iterate through all immediate children of the root. * For each child, I run a DFS to traverse its entire subtree. * During this DFS, every node in that subtree is tagged with that specific child as its second_parent (essentially labeling which main branch of the root it belongs to).

4. The Validation Step After the tree is fully labeled, validating the candidate K takes just O(N) time: * Iterate through all possible nodes i from 1 to N. * Calculate the required pair: target = K - i. * If the target is valid (1 <= target <= N and target != i), we just check their labels: if (second_parent[i] != second_parent[target]). * If they have different branch labels, they don't share the same immediate branch from the root, meaning we found a valid pair for this K! We update our answer me = K.

Complexity: Because we only test 3 candidates when N is odd, we run a standard DFS and a simple linear scan 3 times. * Time Complexity: O(N) * Space/Memory: O(N) for the adjacency list and the second_parent array.

You can check out my implementation here: Submission #397399210

Hope this helps anyone looking for a clean linear-time solution! Let me know if you have any questions about the routing logic.