wsyear's blog

By wsyear, 13 hours ago, In English

2048A - Kevin and Combination Lock

Author: Little09

Hint 1
Tutorial

2048B - Kevin and Permutation

Author: wsyear

Hint 1
Tutorial

2048C - Kevin and Binary Strings

Author: Little09

Hint 1
Hint 2
Hint 3
Tutorial

2048D - Kevin and Competition Memories

Author: cmk666

Hint 1
Hint 2
Hint 3
Tutorial

2048E - Kevin and Bipartite Graph

Author: Little09

Hint 1
Tutorial

2048F - Kevin and Math Class

Author: wsyear

Hint 1
Hint 2
Tutorial

2048G - Kevin and Matrices

Author: cmk666

Hint 1
Hint 2
Hint 3
Hint 4
Tutorial

2048H - Kevin and Strange Operation

Author: JoesSR

Hint 1
Hint 2
Hint 3
Tutorial

2048I1 - Kevin and Puzzle (Easy Version)

Author: Little09

Hint 1
Tutorial

2048I2 - Kevin and Puzzle (Hard Version)

Author: Little09

Hint 1
Hint 2
Hint 3
Hint 4
Tutorial
  • Vote: I like it
  • +85
  • Vote: I do not like it

»
11 hours ago, # |
  Vote: I like it +15 Vote: I do not like it

first

I was one $$$=$$$ sign off from getting $$$E$$$ lol

  • »
    »
    8 hours ago, # ^ |
      Vote: I like it +3 Vote: I do not like it

    Haha me too. I wrote > 2*n instead of >= 2*n lol. Now first time losing rating

»
11 hours ago, # |
  Vote: I like it +36 Vote: I do not like it

I think the $$$O(n)$$$ solution for C is quite interesting. Why not split it into a C2?

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

    I agree

  • »
    »
    11 hours ago, # ^ |
      Vote: I like it -39 Vote: I do not like it
    import java.util.*;
    
    public class Main {
        public static void main(String __[]) {
            var sc = new Scanner(System.in);
            var t = sc.nextInt();
            sc.nextLine();
            while (t-- > 0) {
                var s = sc.nextLine();
                var n = s.length();
                var a2 = new ArrayList<ArrayList<Integer>>();
    
                for (var i = n - 1; i >= 0; i--) {
                    var a1 = new ArrayList<Integer>();
                    a1.add(i);
                    a1.add(i);
                    for (var j = i; j >= 0; j--) {
    
                        // MAIN LOGIC
                        if (s.charAt(n - 1 - i + j) != s.charAt(j)) {
    
                            a1.add(n - 1 - i + j);
                            a1.set(1, j);
    
                        }
    
                    }
                    if (a1.size() > 2) a2.add((ArrayList) a1.clone());
                }
    
                a2.sort((x, y) -> {
                    var xs = x.size();
                    var ys = y.size();
    
                    for (var i = 1; i <= Math.min(xs, ys) - 2; i++) {
                        if (x.get(xs - i) != y.get(ys - i))
                            return x.get(xs - i) - y.get(ys - i);
                    }
    
                    return ys - xs;
                });
    
                if (a2.size() != 0)
                    System.out.println("1 " + n + " " + (a2.get(0).get(1) + 1)
                                       + " " + (a2.get(0).get(0) + 1));
                else System.out.println("1 " + n + " 1 1");
            }
        }
    }
    

    Can anyone please guess the error because of which my code is giving wrong answer on the 7th test case.

  • »
    »
    10 hours ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    I was trying to solve C by explicitly taking XOR from numbers (i.e. binary transformed into decimal) and obviously ran out of memory. And then I came to the $$$O(n)$$$ solution.

    (edited)

    • »
      »
      »
      10 hours ago, # ^ |
        Vote: I like it +12 Vote: I do not like it

      bro skipped a step from taking the xor of numbers of 5000 digits to finding the optimal solution

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

      Even I solved C in O(n). Was able to prove my hypothesis on working with first 0 and first 1 after first 0.

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

    Lol I directly coded the O(n) solution :D Slight observation but I was able to get that correct in one go.

»
11 hours ago, # |
  Vote: I like it +5 Vote: I do not like it

First time ever i solve 5 problems in a div2, i think D is very cool, and i kinda guessed E but good contest overall

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

great contest and tutorial :)

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

Can anyone explain why my D Solution is too slow?

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

    O(m^2) solution is going to give you TLE as m<=3e5

    • »
      »
      »
      10 hours ago, # ^ |
        Vote: I like it +5 Vote: I do not like it

      Thanks for pointing that out. Got tunnel visioned. Later I got this accpeted Here

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

great contest tho I find it wired that F requires such complex data structure (probably it isn't wired and I just lack experience)

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

    It's not complicated structure for F.

  • »
    »
    8 hours ago, # ^ |
    Rev. 2   Vote: I like it +15 Vote: I do not like it

    Honestly a min Cartesian Tree is just a fancy way of refering to the classic problem of finding for each element its first lower neighbours on the left/right.

    Now you can say that each element is the node corresponding to an interval, and all you need to add is to compute the two childs in the tree (which corresponds to the interval splitted by the minimum value), which requires a bit of thinking but no complicated code.

    Finally to manage the DP in the tree you can do simply dfs using the indices of intervals and never explicitly construct the tree, like you would do in a divide and conquer approach.

    All in all it might be a complex idea but it can be implemented easily (you can check my submission if you'd like (which is $$$O(nlog^2)$$$ should you wonder))

»
11 hours ago, # |
  Vote: I like it +4 Vote: I do not like it

Special Thanks to cmk666 for the nice problem 2048D - Kevin and Competition Memories

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

one more div2 contest where i can't solve more than 3 questions.

how should i practice to solve question D in div 2 contests? thanks in advance

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

Anyone tried solving E with below approach.

Each edge can be represented as ordered pair ( i , j ) . where 'i' belongs to left side, and 'j' belongs to right side.

Now, we have total of 2 * n * m such ordered pairs. each of these edge can be actually convert into a vertex. since our graph is bipartite, after we travel one of our edge, next edge direction will be opposite ( if we travel current edge from left to right, next edge we must travel right to left )

=> if I am going from (i,j1) to (i,j2) , i will try to give available color to (i,j2) and then I will keep 'j2' constant and try to find some valid 'i' which is not yet colored and try to color it.

Now start DFS from (1,1) , and if its odd iteration of the we will go from left to right, if it is even iteration, we will go from right to left.

When we go from left to right , we will keep 'i' constant and loop over all the 'j' in the ordered pair ( i , j ) .

When we go from right to left, we will keep 'j' constant and loop over all the 'i'.

We will try to basically color this graph of 2 * n * m vertices,,, with 'n' colors. I tried this approach, but don't know, why does it fail ?

»
11 hours ago, # |
  Vote: I like it +6 Vote: I do not like it

E made me sad.

»
11 hours ago, # |
  Vote: I like it -32 Vote: I do not like it
import java.util.*;

public class Main {
    public static void main(String __[]) {
        var sc = new Scanner(System.in);
        var t = sc.nextInt();
        sc.nextLine();
        while (t-- > 0) {
            var s = sc.nextLine();
            var n = s.length();
            var a2 = new ArrayList<ArrayList<Integer>>();

            for (var i = n - 1; i >= 0; i--) {
                var a1 = new ArrayList<Integer>();
                a1.add(i);
                a1.add(i);
                for (var j = i; j >= 0; j--) {

                    // MAIN LOGIC
                    if (s.charAt(n - 1 - i + j) != s.charAt(j)) {

                        a1.add(n - 1 - i + j);
                        a1.set(1, j);

                    }

                }
                if (a1.size() > 2) a2.add((ArrayList) a1.clone());
            }

            a2.sort((x, y) -> {
                var xs = x.size();
                var ys = y.size();

                for (var i = 1; i <= Math.min(xs, ys) - 2; i++) {
                    if (x.get(xs - i) != y.get(ys - i))
                        return x.get(xs - i) - y.get(ys - i);
                }

                return ys - xs;
            });

            if (a2.size() != 0)
                System.out.println("1 " + n + " " + (a2.get(0).get(1) + 1)
                                   + " " + (a2.get(0).get(0) + 1));
            else System.out.println("1 " + n + " 1 1");
        }
    }
}

Can anyone please guess the error because of which my code is giving wrong answer on the 7th test case.

»
11 hours ago, # |
  Vote: I like it +9 Vote: I do not like it

G is a nice one! ❤️

»
11 hours ago, # |
  Vote: I like it +10 Vote: I do not like it

For F, the constraints don't cut the $$$n \cdot \log^2(a)$$$ solution, but also make it harder for people who are careful.

I spent extra time to optimize out a $$$\log(a)$$$ factor just like the editorial because $$$n \cdot \log^2(a) \approx 8 \cdot 10^8$$$.

If instead the time limit was greater or $$$a = 10^9 \implies n \cdot \log^2(a) \approx 2 \cdot 10^8$$$, I would definitely go for this solution and not waste time. Since I optimized, I failed to finish F by a few minutes.

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

    I didn’t pass with log^2 so it’s kinda a gamble…

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

Was curious about F's solution and heard for the first time about min cartesian tree!! Anyone have any good resources to learn more about it?

»
10 hours ago, # |
  Vote: I like it -10 Vote: I do not like it

can someone please help me with this solution. It fails for tc5

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using db = long double; // or double if tight TL
using str = string;

using pi = pair<int,int>;
#define mp make_pair
#define f first
#define s second

#define tcT template<class T
tcT> using v = vector<T>;
tcT, size_t SZ> using AR = array<T,SZ>;
using vi = v<int>;
using vc = v<char>;
using vs = v<string>;
using vb = v<bool>;
using vll = v<long long>;
using vpi = v<pi>;

#define sz(x) int((x).size())
#define all(x) begin(x), end(x)
#define sor(x) sort(all(x))
#define rsz resize
#define pb push_back
#define ft front()
#define bk back()

#define rep(i,a,b) for (int i = (a); i < (int)(b); ++i)
#define repr(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define each(x,a) for (auto& x: a)

const int MOD = 1e9+7;
const db PI = acos((db)-1);

tcT> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; } // set a = min(a,b)
tcT> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; } // set a = max(a,b)

// inline void dbg(T x) { cerr << x << endl; }

bool cmp(pair<int, int> p1, pair<int, int> p2) {
    return p1.second < p2.second;
}


bitset<32> to_bitset(string s) {
    auto binary = [](char c) { return c == '0' || c == '1'; };
    auto not_binary = [binary](char c) { return !binary(c); };

    s.erase(std::remove_if(begin(s), end(s), not_binary), end(s));

    return std::bitset<32>(s);
}

string to_string(std::bitset<32> bs) {
    return bs.to_string();
}
void solve(int T) {
    cin >> T;
    while (T--) {
        string s; cin >> s;
        int first = -1;
        rep(i,0,s.size()) {
            if (s[i] == '0') {
                first = i;
                break;
            }
        }
        if (first == -1) {
            cout << 1 << " "<< 1 << " " << 1 << " " << s.size() << endl;
        }
        else {
            int req = s.size() - first;
            string subs = "";
            int l = 0, r = req-1;
            int ansl = l, ansr = l;
            string ansres = "";
            while (r < s.size()) {
                subs = s.substr(l, req);
                auto res = to_string(to_bitset(s)^to_bitset(subs));
                if (res > ansres) {
                    ansres = res;
                    ansl = l+1, ansr = r+1;
                }
                r++; l++;
            }
            cout << 1<<" "<<s.size()<<" "<<ansl << " " << ansr << endl;
        }
    }
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int T = 1;
    solve(T);
    return 0;
}

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

    Just replace std::bitset<32> with std::bitset<5007> and the solution passes: 297364634. In the problem, the string length can be up 5000, so the bitset should be capable to store at least 5000 bits.

»
9 hours ago, # |
Rev. 3   Vote: I like it 0 Vote: I do not like it

Why is this code for D failing?


int n, m; cin >> n >> m; int me; cin >> me; vector<int>participants, problems, solved; // only participants with rating greater than mine matter for (int i = 0; i + 1 < n; i++){ int num; cin >> num; if (num > me) participants.push_back(num); } // same thing for problems for (int i = 0; i < m; i++){ int num; cin >> num; if (num > me) problems.push_back(num); } sort(participants.begin(), participants.end()); sort(problems.begin(), problems.end()); // computing how many people solve each problem for (int problem : problems){ int first = lower_bound(participants.begin(), participants.end(), problem) - participants.begin(); solved.push_back(participants.size() - first); } sort(solved.begin(), solved.end()); for (int k = 1; k <= m; k++){ int ans = 0; for (int i = k; i <= solved.size(); i += k) ans += solved[i - 1] + 1; cout << ans << " \n"[k == m]; }
  • »
    »
    9 hours ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    I had a similar implementation which worked : 297364236 I dont think you can ignore problems with lower difficulty than Kevin's skill since you can use them to "pad" contests

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

      bro im gonna be honest i dont even know what am im doing, could you explain what the greedy algorithm the editorial describes is doing ?

      • »
        »
        »
        »
        5 hours ago, # ^ |
        Rev. 2   Vote: I like it +2 Vote: I do not like it

        Consider a problem which has difficulty X such that X > Kevin's skill. Then if the number of people who can solve this problem are Y, this means that if you include this problem in a contest, at least Y people will be ahead of Kevin since Kevin can't solve it.

        If the difficulty X is equal to or less than Kevin's skill, then no one will be able to get ahead of Kevin using only this problem, in which case the number of people ahead of Kevin is 0. So, for each problem P[i] you can calculate how many people can potentially get ahead of Kevin using only P[i] (say we call this value Ahead[i]).

        Now you need to create K groups. Kevin's final ranking in a group will be max(all Ahead[i] values in the group) + 1. For example If the group has Ahead values 0 1 4, that means everyone solves the first problem, the second problem is solved by one person who is not Kevin and the third problem is solved by 4 people but not Kevin. This means that a total of 4 people are ahead of Kevin, giving Kevin 5th rank (Note that the person who solves the second problem is also among the people who solve the third problem, which is why we take max(Ahead[i])). The final answer is the sum of ranks across all groups.

        Now in order to minimize the sum, you must minimize the max(Ahead[i]) in each group which you can do by greedily assigning K values with lowest Ahead[i] in the first group, next K lowest in next group and so on. So if Ahead array is 0 1 3 5 and K = 2, we make groups (0, 1) and (3, 5). The sum of ranks would be max(0,1) + 1 + max(3, 5) + 1 = 2 + 6 = 8

        I hope this didn't confuse you even more lol

    • »
      »
      »
      5 hours ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it

      Wait I think I got it. When constructing the answer we need to take the k problems the least amount of people solved. So we get the k first problems after padding them out. Is this it? I still don't know how the solution doesn't raise TLE though

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

        For each K from 1 to m, you start from (K-1)th index and increment by K as long as the index < m. So for K = 1, there are m operations. For K = 2, m/2 operations and so on which results in MLog(M) complexity. Hence no TLE

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

          yeah turns out we're doing m * (1/1 + 1/2 + 1/3 + 1/4 + ... + 1 / m) operations which is the harmonic series sum thing the editorial mentions, which is log(n) for some reason so ok nice

»
9 hours ago, # |
  Vote: I like it +43 Vote: I do not like it

For E, I found this paper which solves a slightly more general problem of coloring a complete bipartite graph into the minimum number of colors such that each color is a forest.

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

Can someone please help me out where I am going wrong with C: my submission

I get that the first substring will be the entire string, and the second substring will be of the length = length of complete string — position of first 0 from left. But since we only have to find out which such substring gives the maximum XOR, I take a different parameter called 'ans' in my solution and I claim that the substring which gives the higher 'ans' will also give the higher XOR value.

Here is how I am constructing 'ans': I am comparing the portion of two strings which is to be XOR'ed. Starting from the most significant bit, if the corresponding bit in both the strings are 0 and 1 respectively, I am incrementing ans by a larger value (and decrementing if the bits are 1 and 1 respectively since that will decrease XOR value). As I move from left to right, The value with which I increment/decrement ans decreases (since the right bits will have less contribution to the XOR value than the left bits). The substring which gives the maximum 'ans' value will also give me the maximum XOR value. But I am getting wrong answer on test case 2 itself and I am unable to figure out where I am going wrong! Please help

  • »
    »
    9 hours ago, # ^ |
    Rev. 2   Vote: I like it -6 Vote: I do not like it

    Maybe my implementation can help you:


    string s; int n; cin >> s; n = s.size(); bool hasZero = false; for (int i = 0; i < n; i++) if (s[i] == '0') { hasZero = true; break; } if (!hasZero) { cout << 1 << " " << n << " " << 1 << " " << 1 << endl; return; } int first_zero = 0; for (int i = 0; i < n; i++) if (s[i] == '0') { first_zero = i; break; } int best_l = 0; int sz = n - first_zero; for (int l = 0; l <= n - sz; l++) for (int i = 0; i < sz; i++) { if (s[first_zero + i] == '1') { // If at this position of the string we have a 1 if (s[l + i] == '1' && s[best_l + i] == '0') // If the current substring has a 1 and my current answer has a 0, the current substring is worse and should not be processed break; if (s[l + i] == '0' && s[best_l + i] == '1') { // If the current substring has a 0 and the current answer has a 1 I found a better answer best_l = l; break; } } else { // if the original string has a '0' if (s[l + i] == '0' && s[best_l + i] == '1') // if the current substring has a 0 and the answer has 1 then this is worse and should not be processed break; if (s[l + i] == '1' && s[best_l + i] == '0') { // if the current substring has a 1 and the answer has a 0 i found a better answer best_l = l; break; } } } cout << 1 << " " << n << " " << best_l + 1 << " " << best_l + sz << endl;
    • »
      »
      »
      8 hours ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      Thanks for your code, I completely understood it. However, I still haven't understood what is wrong in my implementation.

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

        I think your ans logic is flawed, say you have two candidates for strings, the first one has a better most significant bit and the other one has a worse most significant bit but every other bit is better in the second one. Maybe the way your ans is incremented makes the sum of the second one better than the first one if that makes sense

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

          Ahh now I get it! I have been trying to figure out a flaw in my logic since the last 4 hours, only to find out it was this trivial :')

          Thank you very much for pointing this out!

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

      Please do not post entire solutions in the comments. Makes it very noisy to scroll through the comments. Paste submission links.instead.

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

I hate the fact, that I was debugging F for 40 minutes, because I was getting RTEs on test 3. There was some stupid stack overflow; the recursion was returning a big static object (488 bytes), and after changing it to return an 8 byte pointer, it started working; however, my memory usage was under 350MB, so it should have passed initially.

  • »
    »
    6 hours ago, # ^ |
    Rev. 3   Vote: I like it 0 Vote: I do not like it

    Edit: Codeforces DOES pass -Wl,--stack=268435456 to the linker, however it means the stack limit is always 256MiB regardless of the problem's memory limit. This is totally unreasonable.


    Original comment:

    It is because codeforces's judging environment is Windows, and it seems that they don't pass -Wl,--stask=xxx to the linker, which leads to a stack limit which is smaller than memory limit. I hope MikeMirzayanov could fix it, as more than one contestant faced it during contest time.

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

Good contest,make me promote to IM :)

»
6 hours ago, # |
  Vote: I like it +9 Vote: I do not like it

Little09 Can you elaborate on the $$$O(n\log^2n)$$$ solution for I2? Idk what block convolution is.

  • »
    »
    66 minutes ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    There is a solution of complexity $$$O(n\sqrt{\frac{n\log n}{\omega}})$$$. The general idea is to divide the sequence into chunks for every $$$B$$$ positions, and for each $$$l+r$$$ value find the $$$r$$$ that minimally satisfies the condition. If $$$l,r$$$ belongs to different blocks, enumerating the blocks of $$$r$$$ and then convolving this block with the prefixes tells us which $$$l+r$$$ occur, and then finding the smallest $$$r$$$ within the block. The case where $$$l,r$$$ belongs to the same block is easily solved. Finally, the bitset optimization is performed to obtain a complexity of $$$O(\frac{n^2}B\log n+\frac{nB}{\omega})$$$.

    About $$$O(n\log ^2n)$$$ solution, it comes from JoesSR and it is more difficult and maybe I will add in the Editorial in a few days.

»
5 hours ago, # |
  Vote: I like it -55 Vote: I do not like it

use core::fmt; use std::{ops::Index, fmt::Debug, vec::IntoIter}; pub struct SortedList<T> where T: Ord { _lists: Vec<Vec<T>>, _index_tree: Vec<usize>, _index_tree_offset: usize, _load_factor: usize, _upper_load_factor: usize, _lower_load_factor: usize, _len: usize, } impl<T> SortedList<T> where T: Ord { const DEFAULT_INDEX_TREE_OFFSET: usize = 1<<5; const DEFAULT_LOAD_FACTOR: usize = 1_024; const DEFAULT_UPPER_LOAD_FACTOR: usize = 2_048; const DEFAULT_LOWER_LOAD_FACTOR: usize = 512; fn _default() -> Self { Self { _lists: vec![], _index_tree: vec![0; 2*Self::DEFAULT_INDEX_TREE_OFFSET], _index_tree_offset: Self::DEFAULT_INDEX_TREE_OFFSET, _load_factor: Self::DEFAULT_LOAD_FACTOR, _upper_load_factor: Self::DEFAULT_UPPER_LOAD_FACTOR, _lower_load_factor: Self::DEFAULT_LOWER_LOAD_FACTOR, _len: 0 } } fn _collapse(&mut self, i: usize) { if self._lists.len()<=1 { panic!("Attempting to collapse while self._lists contains only {} lists.", self._lists.len()); } let left = match i>=1 { true => self._lists[i-1].len(), false => usize::MAX, }; let right = match i+1<self._lists.len() { true => self._lists[i+1].len(), false => usize::MAX, }; assert!(left.min(right) < usize::MAX); if left<right { let mut removed = self._lists.remove(i); self._lists[i-1].append(&mut removed); } else { let mut removed = self._lists.remove(i+1); self._lists[i].append(&mut removed); } self._rebuild_index_tree(); } fn _expand(&mut self, i: usize) { if self._lists[i].len() < self._upper_load_factor { panic!("Unnecessary expand at self._lists[{}]", i); } let size = self._lists[i].len(); let removed: Vec<T> = self._lists[i].drain(size/2..).collect(); self._lists.insert(i+1, removed); self._rebuild_index_tree(); } fn _rebuild_index_tree(&mut self) { self._index_tree_offset = Self::DEFAULT_INDEX_TREE_OFFSET; while self._index_tree_offset < self._lists.len() { self._index_tree_offset *= 2; } self._index_tree.fill(0); self._index_tree.resize(2*self._index_tree_offset, 0); (0..self._lists.len()) .for_each(|node| { self._index_tree[node + self._index_tree_offset] = self._lists[node].len(); }); (1..self._index_tree_offset) .rev() .for_each(|node| { self._index_tree[node] = self._index_tree[2*node] + self._index_tree[2*node+1]; }); } fn _index_tree_sum(&self, ql: usize, qr: usize, opt_node: Option<usize>, opt_l: Option<usize>, opt_r: Option<usize>) -> usize { let node = opt_node.unwrap_or(1); let l = opt_l.unwrap_or(0); let r = opt_r.unwrap_or(self._index_tree_offset - 1); if ql<=l && r<=qr { return self._index_tree[node]; } if qr<l || r<ql { return 0; } let m = (l+r)/2; return self._index_tree_sum(ql, qr, Some(2*node), Some(l), Some(m)) + self._index_tree_sum(ql, qr, Some(2*node+1), Some(m+1), Some(r)); } fn _index_tree_add(&mut self, i: usize, val: i32) { let mut node = self._index_tree_offset + i; if val>=0 { self._index_tree[node] += val as usize; } else { self._index_tree[node] -= (-val) as usize; } node /= 2; while node>0 { self._index_tree[node] = self._index_tree[2*node] + self._index_tree[2*node+1]; node /= 2; } } fn _lists_remove(&mut self, i: usize, j: usize) -> T { if i>=self._lists.len() || j>=self._lists[i].len() { panic!("List index out of range. Attempting to remove self._lists[{}][{}]", i, j); } let removed = self._lists[i].remove(j); self._len -= 1; if self._lists.len()>1 && self._lists[i].len() < self._lower_load_factor { self._collapse(i); } else { self._index_tree_add(i, -1); } return removed; } fn _lists_insert(&mut self, i: usize, element: T) { let pos = match self._lists[i].binary_search(&element) { Ok(p) => p, Err(p) => p, }; self._lists[i].insert(pos, element); self._len += 1; if self._lists[i].len() > self._upper_load_factor { self._expand(i); } else { self._index_tree_add(i, 1); } } fn _bisect_right_lists(&self, element: &T) -> usize { if &self._lists[0][0] > element { return 0; } let mut lo = 0; let mut hi = self._lists.len()-1; if &self._lists[hi][0] <= element { return hi; } let mut mid; while lo+1 < hi { mid = (lo+hi)/2; if &self._lists[mid][0] <= element { lo = mid; } else { hi = mid; } } return lo; } fn _locate_kth_element(&self, k: usize) -> (usize, usize) { if k>=self._len { panic!("SortedList: Index out of range."); } let is_leaf_node = |u| { u>=self._index_tree_offset }; let mut cnt = k+1; let mut node: usize = 1; while !is_leaf_node(node) { if self._index_tree[2*node]>=cnt { node = 2*node; } else { cnt -= self._index_tree[2*node]; node = 2*node+1; } } return ( node - self._index_tree_offset, cnt - 1, ); } fn _at(&self, i: usize, j: usize) -> &T { return &self._lists[i][j]; } fn _flat(&self) -> Vec<&T> { self._lists .iter() .fold(Vec::new(), |mut cur, list| { list .iter() .for_each(|element| { cur.push(element); }); cur }) } } impl<T> SortedList<T> where T: Ord { pub fn new() -> Self { Self::_default() } pub fn kth_smallest(&self, k: usize) -> &T { let (i,j) = self._locate_kth_element(k); return self._at(i, j); } pub fn clear(&mut self) { self._lists.clear(); self._index_tree.clear(); self._index_tree.resize(2*Self::DEFAULT_INDEX_TREE_OFFSET, 0); self._index_tree_offset = Self::DEFAULT_INDEX_TREE_OFFSET; self._len = 0; } pub fn insert(&mut self, element: T) { if self._len==0 { self._lists.push(vec![]); self._lists_insert(0, element); return; } let k = self._bisect_right_lists(&element); self._lists_insert(k, element); } pub fn remove(&mut self, k: usize) -> T { let (i,j) = self._locate_kth_element(k); return self._lists_remove(i, j); } pub fn binary_search(&self, element: &T) -> Result<usize, usize> { if self._len==0 { return Err(0); } let i: usize = self._bisect_right_lists(element); if i==0 { return self._lists[i].binary_search(element); } match self._lists[i].binary_search(element) { Ok(pos) => Ok(pos + self._index_tree_sum(0, i-1, None, None, None)), Err(pos) => Err(pos + self._index_tree_sum(0, i-1, None, None, None)), } } pub fn contains(&self, element: &T) -> bool { match self.binary_search(element) { Ok(_) => true, _ => false, } } pub fn len(&self) -> usize { self._len } pub fn is_empty(&self) -> bool { self.len()==0 } pub fn last(&self) -> Option<&T> { if self.len()==0 { return None; } return self._lists.last().unwrap().last(); } pub fn first(&self) -> Option<&T> { if self.len()==0 { return None; } return self._lists.first().unwrap().first(); } pub fn get(&self, index: usize) -> Option<&T> { if self.len()==0 || self.len()<=index { return None; } return Some(self.kth_smallest(index)); } pub fn flatten(&self) -> Vec<&T> { self._flat() } pub fn to_vec(&self) -> Vec<T> where T: Clone { self._lists .iter() .fold(vec![], |mut cur, list| { cur.append(&mut list.to_vec()); cur }) } } impl<T> Default for SortedList<T> where T: Ord { fn default() -> Self { Self::_default() } } impl<T> Index<usize> for SortedList<T> where T: Ord { type Output = T; fn index(&self, index: usize) -> &Self::Output { self.kth_smallest(index) } } impl<T> From<IntoIter<T>> for SortedList<T> where T: Ord { fn from(iter: IntoIter<T>) -> Self { let mut array: Vec<T> = iter.collect(); array.sort(); let sorted_iter = array.into_iter(); let mut sorted_list = Self::default(); sorted_list._len = sorted_iter.len(); sorted_list._lists.push(vec![]); let mut last_list_size = 0; for element in sorted_iter { sorted_list._lists.last_mut().unwrap().push(element); last_list_size += 1; if last_list_size == sorted_list._load_factor { last_list_size = 0; sorted_list._lists.push(vec![]); } } sorted_list._rebuild_index_tree(); sorted_list } } impl<T> From<Vec<T>> for SortedList<T> where T: Ord { fn from(array: Vec<T>) -> Self { Self::from(array.into_iter()) } } impl<T> From<&[T]> for SortedList<T> where T: Ord + Clone { fn from(array: &[T]) -> Self { Self::from(Vec::from(array)) } } impl<T> From<&mut [T]> for SortedList<T> where T: Ord + Clone { fn from(array: &mut [T]) -> Self { Self::from(Vec::from(array)) } } impl<T, const N: usize> From<[T;N]> for SortedList<T> where T: Ord { fn from(array: [T;N]) -> Self { Self::from(Vec::from(array)) } } impl<T> fmt::Debug for SortedList<T> where T: Ord + Debug { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self._flat(), f) } }

can someone tell me why it fails on test 3

»
4 hours ago, # |
  Vote: I like it -12 Vote: I do not like it

CONGRATULATIONS! my friend chenlinxuan0226 reached CM after this contest!

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

"In fact, this is easy to construct"

Even after reading more than 5 times, above statement still hurts my soul.

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

    I think it will be easy, if you make construction this way:

    Our answer should satisfy the following property, if we fix two rows i.e., the nodes on the left side, there should not be greater than two columns of same colours.

    Like this case where there are two columns of (1, 1) which forms cycle for a pair of nodes on left. So, it won't work.

    1....1.....2

    3....3.....4

    1....1.....3

    By trying out small cases and making construction based on this would be easy.

    So, for (n, m = 2 * n — 1), you could always find a case, where there are no two columns of same colour for every possible pair of rows. And this also satisfies for all m <= 2 * n — 1 (Printing the array till m columns).

    for n = 4

    1 1 1 1 2 3 4

    2 2 2 2 3 4 1

    3 3 3 3 4 1 2

    4 4 4 4 1 2 3

    1 2 3 4 1 1 1

    1 2 3 4 2 2 2

    1 2 3 4 3 3 3

    1 2 3 4 4 4 4

»
4 hours ago, # |
  Vote: I like it +9 Vote: I do not like it

Why my stupid $$$\Theta(n\log^2 v)$$$ solution for F ran for just 827ms, can sb hack it or did it just run too fast because of constant factor? 297330202

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

got my first problem C !!!!

i somehow thought of the o(n) and not o(n^2) on C lol

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

Proof (for problem C) of why (1,n) is always one of the substring.

let leftmost '1' occurs at pth position(from right to left) no other substring can have (p+1)th position '1' hence can never exceed the xor of one pair created using (1,n) as one substring.

also 2^k> 2^(k-1)+ 2^(k-2)....... +2+1. so if you could get xor with all bits '1' and with length (p-1) it will still be smaller than which could be generated using (1,n) (pth position '1').

please correct me if i am wrong.

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

Can't we include visual explanation with images in editorial? then many more participants can upsolve the problems and can Improve, i usually find difficulty to understand the text solution.

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

Identity V?

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

Finally, after losing hope so many times. I can now understand "how to understand the problems". I may seem funny/absurd/weird to others, but I'm glad.

Also, it's a great contest. Registered for extra registration and able to understand questions. I almost got the C but missing a piece to complete. Way to go and learn. Hope for great learning !

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

I have a doubt in problem C, if the problem does not say that string starts with '1' does it will change the answer?

I yes how?

  • »
    »
    82 minutes ago, # ^ |
      Vote: I like it +1 Vote: I do not like it

    Well you always want one of the strings to be in the range of [the left most one,1]. So instead of solving on the entire string, you would first check the edge case of all 0s and then just solve the same thing on the substring from where the first 1 ocurrs

»
41 minute(s) ago, # |
  Vote: I like it 0 Vote: I do not like it

Can someone help me identify where I went wrong in this solution 297315319? I believe my solution has a time complexity of $$$O(n^2)$$$, yet I am experiencing a TLE for test case 21. Any assistance would be greatly appreciated.

How my code works
»
26 minutes ago, # |
  Vote: I like it 0 Vote: I do not like it

I had so much fun doing C, firstly I devised O(n^2) solution then I noticed I can use concept of MSB once again and voila got O(n) solution. Spent 1 hour on this though.