FelixArg's blog

By FelixArg, 2 months ago, translation, In English

Thank you for participating! We hope you enjoyed the problems.

2197A - Friendly Numbers

Tutorial
Solution

2197B - Array and Permutation

Tutorial
Solution

2196A - Game with a Fraction

Tutorial
Solution

2196B - Another Problem about Beautiful Pairs

Tutorial
Solution

2196C1 - Interactive Graph (Simple Version)

Tutorial
Solution

2196C2 - Interactive Graph (Hard Version)

Tutorial
Solution

2196D - Double Bracket Sequence

Tutorial
Solution

2196E1 - Fuzzy Concatenation (Easy Version)

Tutorial

2196E2 - Fuzzy Concatenation (Hard version)

Tutorial
Solution

2196F - Indivisible

Tutorial
Solution

For those who come after.

  • Vote: I like it
  • +121
  • Vote: I do not like it

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

Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).

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

Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).

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

Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).

»
2 months ago, hide # |
 
Vote: I like it +5 Vote: I do not like it

Another solution for div1 D is to just simulate the brackets until you fail. At that moment change this bracket to something else (because you don't know what to change it to, keep all (at most 3) possibilities. At the end the one closest to (0, 0) will give you the minimum changes required.

362523300

Truth be told, I did not manage to prove that this is correct. It is mostly intuition from the simplified problem of only one type of paranthesis (only change when prefix is negative and resolve the end). Would be great if someone could prove/disprove/hack this solution

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

    can you explain more to this what exactly do you mean by closest to 0,0

    • »
      »
      »
      2 months ago, hide # ^ |
       
      Vote: I like it +3 Vote: I do not like it

      Assume you have $$$x$$$ open round paranthesis and $$$y$$$ open square paranthesis. Then the minimum number of operations to get a good string is $$$\frac{x+y}{2}$$$. Take the minimum of these values.

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

        Am not a gm like you lmao to understand that little info if you ever get free please describe that method comprehensively I loved that solution with mindist

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

          Consider how to determine if a sequence is valid. Maintain two sums $$$x, y$$$. For (, $$$x \leftarrow x+1$$$; for ), $$$y \leftarrow y+1$$$, and square brackets do the similar operation on $$$y$$$. A sequence is valid if and only if $$$x, y \ge 0$$$ at any moment, and finally $$$x = y = 0$$$.

          For the single bracket type problem, the optimal strategy is to change ) to ( when $$$sum \lt 0$$$. For two types of brackets, an invalid ) might be changed to one of (, [, or ]. Maintain these three results, and in the subsequent process, avoid extra operations as much as possible unless none of these states remain valid.

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

    This looks essentially the same as the official solution. They may lead to the same construction.

»
2 months ago, hide # |
Rev. 2  
Vote: I like it +122 Vote: I do not like it

We can do Div1E in $$$O((n+m)\log (n+m))$$$ time (with no factors of $$$k$$$).

We want to find the maximum $$$d$$$ where:

  • Given $$$p_t$$$ , $$$p_s$$$ , and $$$\ell \geq 1$$$ . We can assume $$$s_{p_s}s_{p_s+1}\dots s_{p_s+\ell-1}=t_{p_t}t_{p_t+1}\dots t_{p_t+\ell-1}$$$ .
  • There exists a substring of $$$s$$$ which matches to the pattern : ($$$t_{p_t}t_{p_t+1}\dots t_{p_t+\ell-1}$$$) + (an arbitrary character) + (the following $$$d$$$ characters)

Consider all the positions $$$q$$$ of substrings of $$$s$$$ such that $$$s_{q-\ell}\dots s_{q-2}s_{q-1} = t_{p_t}t_{p_t+1}\dots t_{p_t+\ell-1}$$$ . These positions form a segment in the suffix array of the reversed $$$s$$$ . Associate the suffix of the reversed $$$s$$$ ($$$s_{q-1}s_{q-2}\dots$$$) with a suffix of $$$s$$$ ($$$s_{q+1}s_{q+2}\dots$$$). Now we just need to find the maximum LCP between the following characters in $$$t$$$ and $$$s_{q+1}s_{q+2}\dots$$$ , but the value $$$q$$$ must be taken from the corresponding segment of the suffix array of the reversed $$$s$$$ .

Eventually, the task is reduced to a typical query: find the minimum element in a subarray $$$(a_l, a_{l+1}, \dots , a_r)$$$ but no less than $$$x$$$ (and also the maximum but no greater than $$$x$$$). This can be solved using a wavelet matrix.

362520685

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

FelixArg Please fixed the given code for div2A. I think it was written for div2B.

»
2 months ago, hide # |
 
Vote: I like it +9 Vote: I do not like it
  • »
    »
    2 months ago, hide # ^ |
     
    Vote: I like it +13 Vote: I do not like it

    And they disable hacks for A-D. and they themselves don't cover all the test cases.

    Anyways, problem set was very good. But they shouldn't disable hacks if they can't cover all edge cases.

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

2196C2 is a wonderful problem!

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

really a bad contest for me can't debug the div 2 B . can anyone one help me to find the test case where this code not working 362482618. my idea is that all the same elements should be consecutive in array a,and there should not be any diagonal intersection ie- p=1,2 a=2,1 and after storing the index of all the same elements. I will check if the p[i]->index of i in the permutation is in the range of min(i)-1 and max(i)+1,where min(i) is the minimum index of i in the array a and max(i) is the maximum element in the array a. because we can copy one forward and one backward . if i is not present in the array leave it.

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

I found a binary search solution for div2A. The idea is that suppose an infinite sequence of integers where $$$i$$$th element of the sequence is $$$i - d(i)$$$ where $$$d(i)$$$ equals to the sum of the digits of $$$i$$$. Then this sequence will be non-decreasing. So we can binary search for $$$x$$$ in this sequence taking the lower bound and upper bound in a way such that any $$$x$$$ in the given range $$$1≤x≤$$$$$$10$$$$$$9$$$ can be found if present. If $$$x$$$ is present, then the answer is $$$10$$$, otherwise $$$0$$$. You can see my submission 362438894 for implementation. In this code, I have also utilized the fact that $$$x$$$ must be divisible by $$$9$$$ to be in the sequence, which i guess was not necessary to check.

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

My idea for div2 D was to speedup the bruteforce method and avoid recalculation. When iterating over k for $$$j = i + k \cdot a_i$$$, for a given $$$i$$$, we will do the calculations considering the pair $$$(a_i, i \ mod \ a_i)$$$. This means that for any index $$$j$$$ that we encounter in further iterations in which $$$(a_j, j \ mod \ a_j) = (a_i, i \ mod \ a_i)$$$ we can skip it, as we have previously calculated its pairings. The idea behind that is that for all indices with this pairing, they would go through the same $$$j$$$'s and have the same value for contributing to the equation.

When finding such a pair which has not been calculated previously, we can maintain a set with all indices $$$j$$$ where $$$a_j=a_i$$$ and incrementing the answear if $$$j-a_i \cdot a_j$$$ is in the set.

My code: 362526064

The complexity is roughly $$$O(n \sqrt{n} log(n))$$$, i feared receiving a tle but then i noticed that it would be fast enough with 5 minutes for the contest ending and got AC.

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

    You can use an unordered_set instead of an set, which has an amorized time complexity of O(1) per insertion and query. The only moment when you want to use a normal set is when you want to remove/query the largest/smallest element, or you care about the elements being sorted, neither of which you do in this case.

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

      After i made this comment i had actually tried submiting with a unordered_set to see if it would gain some performance, but it actually performed worse. I had this experience a lot when switching between set and unordered_set because normally the test cases are made in such a way that all the element may go to the same bucket or it happens that you get really unlucky and some buckets start getting a little too dense, so i normally use set by standard.

      I also noticed that i didn't really needed a set, and could just use an auxiliary vector that said if an element was already considered in some other iteration, thus making the algorithm work in $$$O(n\sqrt{n})$$$. Here are the subimissions:

      on-contest with set (734ms): 362526064

      using unordered_set (1171ms): 362541967

      optimized with no set (359ms): 362705070

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

        You're right — when accessed many times, but not with many distinct elements unordered_set offen does end up slower thans set, but over 90% of the time you can just use a bitset which is always faster (you just have to remember that bitset<200'000> b is linear and so is setting it to 0). If you change your vector to bitset, you go down to 328ms (366405742). The difference here is small, but visible and in some cases can be much larger, so it's usually better to use a bitset or a vector<char> when you need to dynamically change the size

»
2 months ago, hide # |
 
Vote: I like it +59 Vote: I do not like it

I believe the memory limit of E2(div1) is too small. You will immediately get MLE if you build two SAMs.

»
2 months ago, hide # |
Rev. 3  
Vote: I like it 0 Vote: I do not like it
void solve(){
    //for div2D
    int n;
    cin>>n;
    vector<int> a(n);
    int ans=0;
    forn{cin>>a[i];}
    forn{
        int c=a[i];
        int j=i-c;
        int count=1;
        while(j>=0&&count<a[i]){
            if(a[j]==count){
                ans++;
            }
            j-=c;
            count++;
        }
        j=i+c;
        count=1;
        while(j<n&&count<=a[i]){
            if(a[j]==count){
                ans++;
            }
            j+=c;
            count++;
        }
    }
    print(ans);
}
»
2 months ago, hide # |
 
Vote: I like it +16 Vote: I do not like it

There's a $$$O(m\sqrt{n\Sigma})$$$ for div1E, where $$$\Sigma = 26$$$ is the size of alphabet. For a string with length $$$L$$$, there's at most $$$L\Sigma$$$ different possible strings, and we maintain all of their positions in SAM. When the length $$$L$$$ exceed a threshold $$$B$$$, do the bruteforce in $$$O(n)$$$ mention in the solution for E1.

Here the time complexity is $$$\frac{m}{B}\cdot \Sigma \cdot B^{2} + \frac{m}{B} \cdot n$$$, which is $$$O(m\sqrt{n\Sigma})$$$ when $$$B = \sqrt{\frac{n}{\Sigma}}$$$. The first part of the solution is not full and the solution is easy to squeeze.

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

I wrote a brute-force for div1 E1. The time complexity is O(n*m) and I passed by making constant number small.

362519663

Can this be hacked?

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

In the Div2A editorial, why do we need to check the range from x to x + 83? The problem states that x is between 1 and 10^9, so shouldn’t we only need to check i in the range from x to x + 81?

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

    That is something you will notice in various solution. It is just a safe redundancy to make sure there is no runtime or logical error. The most used example that I have seen is when the author creates an array a[N], where N would be 2e5 + 10. Although, the size may never exceed 200,000. It is just there to make sure that any unexpected error does not appear.

    In this case, it does not matter that we check for 82 and 83. It is just there. If you observe other submission for same problem, you may find many using x to x + 100.

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

      Got that. Thanks for clarification :). Yes I have seen solution of red coders they used till x+100.

»
2 months ago, hide # |
 
Vote: I like it -10 Vote: I do not like it

ConstraintForces

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

Tried hell a lot to debug div2B, pls help

my approach: in a map i store, the indices where each element appeared in the permutation array. an integer pivotIndex, indicates, till now, which was the last element from which we copied values. [to be precise, if I am at some index i, then pivotIndex represents the index of the element used to correct the p[i].] i iterate through the permutaion array, there will be three possibilities

  1. p[i] = a[i], then pivotIndex = i; i++;
  2. p[i] != a[i], then a. mp[a[i]] < i and mp[a[i]] >= pivotIndex, then we can copy required value, new pivotIndex = mp[a[i]]; i++;

b. mp[a[i]] > i, then check if till required index, all elements are a[i] only, if yes, very nice new pivotIndex = mp[a[i]];

else not possible

// my soln code
void solve()
{
    num n; cin >> n;
    vector<num> p(n);
    map<num, num> mp;
    for(int i = 0; i < n; i++)
    {
        cin >> p[i];
        mp[p[i]] = i;
    }
    int pivotIndex = 0;
    vector<num> a(n); for(auto& x : a) cin >> x;
    bool solved = true;
    for(int i = 0; i < n; i++)
    {
        if(p[i] == a[i]) {pivotIndex = i; continue;}
        else
        {
            if(i > 0 && mp[a[i]] < i && mp[a[i]] >= pivotIndex) {p[i] = a[i]; pivotIndex = mp[a[i]];}
            else if(i < n-1 && p[i+1] == a[i]) {p[i] = a[i]; pivotIndex = i+1;}
            else if(i < n-1 && mp[a[i]] > i)
            {
                int j = i+1;
                bool possible = true;
                while(j!=mp[a[i]])
                {
                    if(a[j] != a[i]) {possible = false; break;}
                    else {p[j] = a[i]; j++;}
                }
                if(possible) {p[i] = a[i]; i=j-1; pivotIndex = mp[a[i]];}
                else {solved = false; break;}
            }
            else {solved = false; break;}
        }
    }
    cout << (solved ? "YES\n" : "NO\n");
}
»
2 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

I tried C) fraction by say let say we start with 10,14 now its not 2/3 so we find next 2/3 ratio which is 8 and 12, now alice wants to make it 7 ( 8-1) as soon as possible, while Bob only has to made 14 to 12, so Bob needs 2 Alice needs 3, thats not possible even if Alice plays first, so Bob wins, this approach was not working for this big sample test case, 7000000000000000 10487275715782582, as I was not able to find which is the next closest p/q=2/3 ratio values of p and q are, so I used a loop for it but that loop is not stopping so I took some help from claude but still its not working this is my https://mirror.codeforces.com/contest/2197/submission/362586660

code const fs = require('fs');

const data = fs.readFileSync(0, 'utf8').trim().split(/\s+/);
let w = 0;

const T = Number(data[w++]);

for (let t = 0; t < T; t++) {

    const p = BigInt(data[w++]);
    const q = BigInt(data[w++]);

    const half = p / 2n;

    if (q === half * 3n) {
        console.log('Bob');
        continue;
    }

    if (p >= q) {
        console.log('Alice');
        continue;
    }

   // let count = (half * 3n > q) ? half - q / 3n : 0n;

    let count = (half * 3n > q) ? (half * 3n - q + 2n) / 3n : 0n;

    const req1 = (half - count) * 2n;
    const req2 = (half - count) * 3n;

    const diff1 = (p - req1) + 1n;
    const diff2 = q - req2;

    if (diff2 < 0n) {
        console.log('Alice');
        continue;
    }

    if (diff1 + 1n <= diff2)
        console.log('Alice');
    else
        console.log('Bob');
}
  • »
    »
    4 weeks ago, hide # ^ |
     
    Vote: I like it 0 Vote: I do not like it

    hey here is how i thought about the problem

    bob will in if any value k is such that by p-k/q-k = 2/3 meaning we took 2/3 this ratio then multiplied both up and down with some value 'm' then added k to both . so by substracting k now from p,q they both reaches the desired value where p/q=2/3

    now lets say p=2m+k and q=3m+k so q-p=3m+k-2m-k=m there fore we now need to check if p and q gives exactly same reminder with m or not( k) if so then we are happy and then we check when p and q divided with m does we really get 2 and 3 ....and we are done this was my approach but it didnt worked too sad

    https://mirror.codeforces.com/contest/2197/submission/367139516

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

Loved the contest but its sad that Div2D, people got their n^2 sol passed.

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

This is my thought process when writing Div1 D:

We can obviously think of a wrong simple greedy approach: remove all legal bracket matches, and it is easy to find that the remaining ones need to be paired up, so we can directly divide the number of remaining ones by 2

We can find an obvious counterexample to prove the approach is incorrect: when the sequence of parentheses we remove is )(, no matter what, we need to perform two operations to make it valid.

However, we found that this situation is very rare, and the approach only goes wrong when the parenthesis sequence grows into a pattern like )))(((. Therefore, after special handling, this problem can be solved

  • »
    »
    2 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it +6 Vote: I do not like it

    I did something somewhat similar, but more convoluted. In the first traversal, pair up and "remove" those elements — 0 cost. Then, no pair remains and we need at least 1 operation to make each pair. Hence, the answer is at least half of the amount of remaining chars. It turns out this lower bound can almost always be achieved. And if it can't, there is only one more case: the lower bound + 1 (because a single pair requires 2 operations).

    Call the chars '[' and '(' as S (start). Call the charss ')' and ']' as E (end). It is possible to prove that the extra cost occurs iff the amount of Es is odd and the rightmost E occurs before the leftmost S.

    Hence, the problem is reduced to making the optimal pair ups in the first step: let's try to let the leftmost remaining '(' or '[' (i.e S) as to the left as possible. The opposite for ')', ']' (i.e E). A simple greedy works: traverse from right to left in terms of the starting chars. For the ending chars, mantain a stack.

    • »
      »
      »
      2 months ago, hide # ^ |
       
      Vote: I like it +3 Vote: I do not like it

      Essentially, they are the same.

      The essence of my approach is to pair brackets in the same direction, while yours essentially involves pairing those in different directions.

      It is easy to prove that the ultimate cost of these two approaches is the same. However, my approach does not require actual pairing and can directly compute the answer in $$$O(1)$$$ (of course, during the competition, I was too lazy to write two pointers to determine positions, so I directly sorted and took the index position. Therefore, my code runs in $$$O(n\log n)$$$, but it could easily run in $$$O(n)$$$)

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

My Div2 A solution:

Let's think about denoting $$$y$$$ in the decimal notation. If $$$y = 100 a_2 + 10 a_1 + a_0 \; (0 \le a_i \le 9)$$$, then $$$d(y) = a_2 + a_1 + a_0$$$, so $$$x = y - d(y) = 99 a_2 + 9 a_1$$$.

More generally, if $$$y$$$ is denoted as: $$$\displaystyle y = \sum_{i=0}^n 10^i a_i \; (0 \le a_i \le 9)$$$, then $$$\displaystyle x = \sum_{i=1}^n (10^i - 1) a_i$$$. Note that $$$a_0$$$ does not appear in $$$x$$$, because $$$(10 ^ 0 - 1)a_0 = 0$$$. Since $$$x \le 10^9$$$, having $$$n = 9$$$ is sufficient.

Therefore, for every $$$a = [a_1, a_2, \ldots, a_9]$$$ such that $$$\displaystyle x = \sum_{i=1}^9 (10^i - 1) a_i$$$, you have $$$10$$$ different numbers of $$$y$$$ that satisfies $$$y - d(y) = x$$$ (you have $$$10$$$ here because you can choose $$$a_0$$$ freely).

It turns out the representation of $$$a$$$ is unique for $$$x$$$ that can be denoted in the above way.

Proof. The maximum value that can be represented in $$$m$$$ digits is:

$$$\begin{align*} M &= \sum_{i=1}^m (10^i - 1) \cdot 9 \\ &= 9 \left( \frac{10 (10^m -1)}{9} - m \right) \\ &= 10(10^m - 1) - 9m \\ &= 10^{m+1} - 10 - 9m. \end{align*}$$$

The minimum unit of the $$$(m+1)$$$-th digit is $$$\displaystyle 10^{m+1} - 1$$$, which is larger than $$$M$$$. This means that you can greedily determine the values of $$$a_i$$$ from the higher digits $$$(a_9, a_8, \ldots, a_1)$$$ without negative consequences. So, you can consider this $$$a$$$ as some form of positional notation system, where only some set of numbers can be represented.

So, the final answer is $$$10$$$ if you can find a suitable $$$a$$$ with the above greedy method. Otherwise the answer is $$$0$$$.

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

B is a great problem

»
2 months ago, hide # |
 
Vote: I like it +14 Vote: I do not like it

I am so consufed about Div1E1. With the limitations as they are a light-weight $$$O(nm)$$$ solution passes with flying colors: 362473782.

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

Can someone help me with div2.E? I just can't find the mistake. WA on test 7.

»
2 months ago, hide # |
 
Vote: I like it +1 Vote: I do not like it

For the div2D, why is it enough to check upto k < sqrt for a[i] < sqrt? Isn't it possible that there are some answer where k >= sqrt?

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

    For the case where a[i]=sqrt, let's say that k is some a[j] where j then the pair (j,i) will be counted once while iterating for a[j] (as if a[j]>=sqrt we iterate in both directions).

    Similarly if j>i it will be counted.

»
2 months ago, hide # |
Rev. 4  
Vote: I like it 0 Vote: I do not like it
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define srt(a) sort(a.begin(), a.end())
    #define srtr(a) sort(a.rbegin(), a.rend())
    #define cyes cout<<"YES"
    #define cno cout<<"NO"
    #define pii pair<int,int>
    #define deb(a) for(int x:a) cout<<x<<" "
    #define rev(a) reverse(a.begin(), a.end())

    vector<int> qry(int k){
        cout<<"? "<<k<<endl;
        int q; cin>>q;
        vector<int> a;
        if(q==0) return a;
        for(int i=0; i<q; i++) {int x; cin>>x; a.push_back(x);}
        return a;
    }

    void solve(){
        int n;
        cin>>n;
        
        vector<int> path_len(n+1);
        path_len[1]=1;
        vector<pii> adj;
        int k=2;
        while(1){
            vector<int> p=qry(k);
            int q=p.size();
            if(q==0) break;
            if(q>=2) adj.push_back({p[q-2], p[q-1]});
            for(int i=0; i<q-1; i++){
                path_len[p[i]]++;
            }
            if(path_len[p[q-1]]==0) path_len[p[q-1]]++;
            k+=path_len[p[q-1]];
        }
        
        cout<<"! "<<adj.size()<<endl;
        for(auto [u,v] : adj) cout<<u<<" "<<v<<endl;
    }

    int32_t main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        int tc;
        cin>>tc;
        while(tc--){
        solve();
        //cout<<endl;
    }

        return 0;
    }

Can anyone help me find where i am going wrong and a counter example would be really appreciated where my code takes more than (n+m) queries. My logic may be entirely or partially incorrect. Thanks!

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

Loved the problem Div2/E2 :3

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

Can someone tell me why my same solution for Div2D is giving tle when using map 362858481 but passes when using set 362858833 ?

Edit: I found the problem.

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

In div2D, isn't it a typo?

"If $$$a_i \geq B$$$ and $$$a_j \lt B$$$, then the pair will be counted when we iterate through candidates for j;" — shouldn't it be "candidates for i"?

I assume i < j and for $$$a_j \lt B$$$, when j is fixed, only indices i>j would be considered (according to strategy "iterate through candidates only forward"). If i would be fixed instead, we're guaranteed there won't be more than $$$\lceil\sqrt{n}\rceil$$$ checks (total for both sides, forward and backward) for j ("it is $$$\frac{n}{B}$$$") and that mentioned pair would be covered.

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

can someone please explain div2 D in simpler terms

  • »
    »
    2 months ago, hide # ^ |
    Rev. 2  
    Vote: I like it +3 Vote: I do not like it

    we want a[i] * a[j] = j — i

    let's make an assumption, a[i] & a[j] are both larger than sqrt(j — i), then, a[i] * a[j] would be larger than j — i. Hence our assumption is wrong, and the opposite of our claim is true, i.e. either a[i] <= sqrt(j — i) or a[j] <= sqrt(j — i). (If you know DeMorgan's law it'll be clear how we inverted the statement).

    by the previous statement, we can pair an element <= sqrt(n) with an element <= sqrt(n). And, we can also pair an element <= sqrt(n) with an element >= sqrt(n). These two scenarios are allowed, but we can't pair two elements >= sqrt(n).

    iterate through the elements and call the current element x.

    if x >= sqrt(n): we need an element y with a distance d from the current element such that x * y = d. From the equation we see that d is a multiple of x. Hence, x <= d = x * y <= n — 1 (the farthest pair possible)

    rewriting, x <= x * y <= (n — 1) / x --> 1 <= y <= (n — 1) / x, we said that x >= sqrt(n), that means the worst case for the value of y is sqrt(n) (plugging the smallest value of x = sqrt(n) to make (n — 1) / x as large as possible).

    You can iterate through the possible values of y, setting d = x * y, and checking if the element behind the current element by d equals y, or the element in front of you by d equals y.

    If x <= sqrt(n): we want to pair it with an element <= sqrt(n), and not with an element >= sqrt(n) since in the previous part we did that already.

    since we want to pair it with an element <= sqrt(n), we can just brute force this value (call it y). 1 <= y <= sqrt(n). We want an element that equals y with a distance x * y from the current element, rather than checking the indices of y in the array, we can instead use the info that d = x * y and check the element behind me by d and in front of me by d and seeing if it equals y or not. (you need to handle the collisions btw)

    I've commented an another solution below you maybe it'll make sense. Hope that helped :>

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

Another solution for B div1:

let d be the the distance j — i (d = j — i), x = a[i], y = a[i].

x * y = d.

let x = min(x, y), y = max(x, y).

we know that x <= sqrt(d) and y >= sqrt(d) ==> y ^ 2 >= d.

we also know that d % y = 0, i.e. d = c * y where c is some constant. Hence, y <= d.

since d is the difference of the indices, it's max value is n — 1, we can write it as d <= n for the sake of simplicity.

y <= d <= min(n, y ^ 2), but d = c * y

y <= c * y <= min(n, y ^ 2), dividing by y we get

1 <= c <= min(n / y, y), that worst case for min(n / y, y) is y = sqrt(n). Hence, 1 <= c <= sqrt(n).

we can iterate through the elements of the array supposing the current element is the max between the elements in the pair (i.e. y in the explanation), and brute forcing the value of c to get every possible value of d as d = c * y.

C++ code
»
2 months ago, hide # |
Rev. 2  
Vote: I like it 0 Vote: I do not like it

I'm afraid not even the problem writers know what is going on on C2 — Interactive Graph. Evidence of this is the fact that, on their solution, they compute the longest common prefix of the vectors $$$prev$$$ and $$$cur$$$, but that is not needed because the longest common prefix always has length $$$cur.size()-1$$$. Also, they talk about "connected components" on the editorial, which doesn't help much, because the exercise doesn't have connected components.

My take on their solution is the following:

The sequence of paths in lexicographical order simulates a lexicographical DFS traversal of the DAG. Indeed, when you do a query $$$k$$$, the interactor returns the call stack at the moment $$$k$$$.

With this, we sketch the general idea: we will do a DFS over the DAG, but we will try to avoid visiting a vertex twice (this way we get linear complexity).

Let's do queries from $$$k = 2$$$, then $$$k+1$$$, $$$k+2$$$, and so on, until we visit a vertex for the second time. During that process, let's also keep at what $$$k$$$ a vertex first appeared, and at what $$$k$$$ it left the stack. To do that, we only need the current DFS stack $$$p$$$ and the previous one $$$prev$$$. Notice that the longest common prefix of those stacks is always $$$p.size()-1$$$, because $$$p$$$ was made by removing elements from the back of $$$prev$$$ and then appending a new element.

Whenever we visit a vertex $$$u$$$ for the second time, we already know how many paths start from it: that amount is $$$timeOut[u] - timeIn[u]$$$. So, instead of querying at $$$k+1$$$ now (which will visit those paths), let's go to $$$k + timeOut[u] - timeIn[u]$$$ instead. This will skip exactly all the paths that start on $$$u$$$, and this will effectively make our DFS go to the vertex after $$$u$$$ in DFS order.

This algorithm does exactly the walk a DFS (without vertex repetition) would do, and therefore, the edges of the graph will be the ones made by the 2 last vertices of $$$p$$$ (check code for more details).

Submission

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

FOR THOSE WHO COME AFTER...

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

The editorial is not linked to the round

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

Can someone read my solution for Div2/E1 (Interactive Graph — Simple version) and please explain how the number of queries made by my solution never exceeds 32*(n+m)?

I am unable to mathematically prove my solution's optimality as it tends to get quite rigorous at least for me. I am not even sure if my solution is optimal and whether if it might get hacked by some test case even if it gets accepted for now.

Intuition for my solution: I begin with a linear iteration where I start with the first path (i = 1). You can make an observation that while doing so, if a particular vertex appear at the same position in a series of consecutive paths and then it changes its position or does not appear in the next path at all, that means the entire sub-tree from that vertex has already been encountered and we can store the edges involved in that sub-tree since we iterate through all the paths from that vertex for the first time. Then, we also store the number of paths that originate from that vertex in count array (in my solution) because if that vertex appears for another time, we can directly skip to the path i = i+count[vertex] since we have already encountered the entire sub-tree from that vertex so there is no new edge to be stored.

Please go through my solution to understand what I am talking about.

Submission: 364466471

»
13 days ago, hide # |
 
Vote: I like it 0 Vote: I do not like it

Some additional notes on the editorial solution for 1D (below $$$k$$$-pair denotes a pair which costs $$$k$$$ to make correct):

  1. The fact that we want to maximize $$$0$$$-pairs is not immediately obvious because whether a $$$2$$$-pair is necessary depends on the $$$0$$$-pairs that we select. For instance, for the string $$$())(()$$$, we could either form the pairs $$$[(), )(, ()]$$$ for a cost of $$$0 + 2 + 0$$$ or the pairs $$$[(), )), ((]$$$ for a cost of $$$0 + 1 + 1$$$. However, we can make the following exchange argument: consider two matchable brackets $$$($$$ and $$$)$$$ such that both are in either $$$1$$$-pairs or $$$2$$$-pairs. We claim that it cannot be worse to pair these brackets together into a $$$0$$$-pair, and pair their previous brackets together into a new pair. This is clearly true because the original cost is at least $$$1 + 1$$$, while the new cost is at most $$$0 + 2$$$. From this, we get that indeed, we should select an LPS for both strings. Alternatively you could derive this from the fact that there exists at most 1 2-pair, but this approach feels more intuitive and generalizable to me.
  2. Nonetheless, it's still not obvious which LPS to pick. Here, we can make yet another exchange argument. Let a matched bracket be any bracket in a 0-pair, and an unmatched bracket be any other bracket. Then, we claim that if there exists an unmatched $$$)$$$ between any $$$0$$$-pair, it's not worse to put this $$$)$$$ into the $$$0$$$-pair instead. For instance, if we have the string $$$()()$$$ and the pairs $$$()$$$ and $$$)($$$, it's definitely not worse to swap the pairs to $$$()$$$ and $$$()$$$. From this observation (and a symmetric one for left brackets), the LPS is uniquely determined.