Блог пользователя BledDest

Автор BledDest, история, 19 месяцев назад, По-русски

2069A - А был ли массив?

Идея: BledDest

Разбор
Решение (BledDest)

2069B - Множества незнакомцев

Идея: adedalic

Разбор
Решение (adedalic)

2069C - Красивая последовательность

Идея: BledDest

Разбор
Решение (Neon)

2069D - Палиндромное перемешивание

Идея: BledDest

Разбор
Решение (Neon)

2069E - A, B, AB и BA

Идея: adedalic

Разбор
Решение (adedalic)

2069F - Включение графа

Идея: BledDest

Разбор
Решение (BledDest)
  • Проголосовать: нравится
  • +56
  • Проголосовать: не нравится

»
19 месяцев назад, скрыть # |
Rev. 2  
Проголосовать: нравится +39 Проголосовать: не нравится
»
19 месяцев назад, скрыть # |
Rev. 2  
Проголосовать: нравится -41 Проголосовать: не нравится

A ~ E all have tag "greedy". I think it might be better to swap E and F so that programming skills can be improved as well.

  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    can you pls tell me how to do C using greedy? I scratched my head over C for $$$1.5$$$ hrs staright (cuz i do not know dp :/)

    • »
      »
      »
      19 месяцев назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится

      Actually you can find that a beautiful sequence in this condition shows like this:

      $$$1,2,2,2,\cdots,2,2,3$$$

      count the sequence. That's all.

    • »
      »
      »
      19 месяцев назад, скрыть # ^ |
       
      Проголосовать: нравится +4 Проголосовать: не нравится

      You can see dynamic programming as splitting the problem into multiple states, each state representing the solution to a subproblem of the main problem. The splitting should be done in a way that solving one subproblem makes solving the next subproblem easy (this is called a transition).

      One of the usual way to split the problem is to cut the array you're given at some index and calculate the value for this shorter array. That way if you know the value for the subarray from index $$$1$$$ to $$$i$$$, it can be easy to calculate the value for the subarray from index $$$1$$$ to $$$i+1$$$.

      For problem C, you know the beautiful sequences look like $$$1, 2, 2, ..., 2, 2, 3$$$. One way to construct such a sequence is to start with a $$$1$$$, then add any number of $$$2$$$s you want and finally end with a $$$3$$$. This gives us three different states for our dp (called state $$$j$$$ in the editorial). Then there are three different transition for each index $$$i$$$ :

      • if $$$s_i$$$ is $$$1$$$ you have one more $$$1$$$ to start a sequence with, so $$$dp_{i+1,1} = dp_{i,1}+1$$$
      • if $$$s_i$$$ is $$$2$$$ you can add one more $$$2$$$ to one of the available sequences (from state 1 or state 2), you can also choose not to add a $$$2$$$, so $$$dp_{i+1,2} = 2*dp_{i,2}+dp_{i,1}$$$
      • if $$$s_i$$$ is $$$3$$$ then you can choose to end all sequences from state $$$2$$$, so $$$dp_{i+1,3} = dp_{i,3}+dp_{i,2}$$$.

      The number you're looking for is the count of finished sequences at index $$$n$$$ so $$$dp_{n,3}$$$.

      • »
        »
        »
        »
        19 месяцев назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится

        can some one please help me understand the transition when si = 2, I didnt get

        • »
          »
          »
          »
          »
          19 месяцев назад, скрыть # ^ |
           
          Проголосовать: нравится +1 Проголосовать: не нравится

          If $$$s_i=2$$$, then you want to find all ways of creating a sequence of the form $$$1, 2, 2, ...$$$. There are three possibilities :

          • First one is to have a sequence containing only $$$1$$$ and add $$$s_i$$$ to the sequence, this is $$$dp_{i,1}$$$ possibilities
          • Second one is to have a sequence of the form $$$1, 2, 2, ...$$$ and add $$$s_i$$$ to the sequence, this is $$$dp_{i,2}$$$ possibilities
          • Third one is to have a sequence of the form $$$1, 2, 2, ...$$$ and not add $$$s_i$$$ to the sequence, this is also $$$dp_{i,2}$$$ possibilities

          You add up all possibilities and you get $$$dp_{i+1,2}=2*dp_{i,2}+dp_{i,1}$$$

      • »
        »
        »
        »
        19 месяцев назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится

        Do you know some resources using which i could practice such dp on subsequences problems??

    • »
      »
      »
      19 месяцев назад, скрыть # ^ |
       
      Проголосовать: нравится +1 Проголосовать: не нравится

      Another way you can do it is like this: iterate from right to left, and store a current variable and when you

      • see a $$$2$$$, multiply your current variable by 2 because all the subsequences to the right can either contain the two or not.

      • see a $$$3$$$, add 1 to your current variable to start a new chain of subsequences ending at that $$$3$$$.

      • see a $$$1$$$, just add the current variable to your total result since everything else is accounted for.

      The only problem is that you also count the subsequences $$$1, 3$$$, so just whenever you encounter a $$$1$$$, subtract off all $$$3$$$ s that have appeared after it.

  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится +27 Проголосовать: не нравится

    My experience on educational rounds is that the last problem is often easier than the second last problem if you have knowledge about many data structures/algorithms.

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Awesome contest!!!

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +11 Проголосовать: не нравится

F is way too standard for experienced coders(especially Chinese),shouldn't appear at this position.

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +17 Проголосовать: не нравится

Super slow editorial!

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +14 Проголосовать: не нравится

Lighting slow editorial

But the problems were very interesting

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

thanks for FAST editorial!

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Why can't we use DSU with rollbacks together with paths compression?

  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится +8 Проголосовать: не нравится

    What is this method(DSU with rollbacks)? Resources please!!

    • »
      »
      »
      19 месяцев назад, скрыть # ^ |
      Rev. 2  
      Проголосовать: нравится +16 Проголосовать: не нравится

      When using DSU you have two functions

      find(x) — find the leader of the set that contains $$$x$$$ (not really important for rollbacks)

      unite(x, y) — unite sets containing $$$x$$$ and $$$y$$$ respectively

      The thing with rollbacks is you want to undo the unite(x, y) operation.

      If you look at the following code for this function

      void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (size[x] < size[y]) swap(x, y);
        parent[y] = x;
        size[x] += size[y];
        components--;
      }
      

      you can see we do $$$O(1)$$$ changes (last three lines of function).

      We can save these changes in stack-like structure and when we need to rollback we can easily do it by reading the top tuple of the stack.

      Here we can just save pairs $$$(x, y)$$$ and do the following:

      void rollback(int x, int y) {
        parent[y] = y;
        size[x] -= size[y];
        components++;
      }
      

      More about this:

      https://cp-algorithms.com/data_structures/deleting_in_log_n.html

      https://usaco.guide/adv/offline-del?lang=cpp

      • »
        »
        »
        »
        19 месяцев назад, скрыть # ^ |
        Rev. 2  
        Проголосовать: нравится 0 Проголосовать: не нравится

        Thanks for detailed reply, but as I understood, the main thing is not in rollbacks structure. If we had paths compressions, it's anyway some changes in arrays size and par, so we can just push pairs {v, par[v]} and {v, sz[v]} on stack before operations and rollback them easily, even with path compression. I think in DCP offline case, as tfg mentioned, it`s redundant, because anyway after rollback we decompress paths, so it seems like we dont achieve alpha in asymptotics and it stays log n anyways.

  • »
    »
    19 месяцев назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится +16 Проголосовать: не нравится

    You can but it won't change the complexity. As long as you still do union by rank or union by size.

  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится +19 Проголосовать: не нравится

    Of course you can't.

    If only path compression is implemented (without union by rank), there exists a possibility of generating a chain of length O(n).

    Although amortized analysis suggests that one only needs to pay a single $$$O(n)$$$ cost for path compression, after which all subsequent queries achieve $$$O(1)$$$ time complexity,

    the existence of rollback operations fundamentally breaks this guarantee! A single rollback operation could nullify the effects of previous path compressions.

    This occurs because amortized complexity and persistence are inherently conflicting concepts—persistence invalidates the assumptions of amortized analysis.

    For similar reasons, data structures like the Splay Tree cannot be made persistent either.

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Can someone explain the dp transition equation of problem C.

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +7 Проголосовать: не нравится

For problem D, I have an alternate solution for the 2nd half after you cast out the prefix and suffix of the original string. When a string is palindrome, for n/2 first character, the number of each character is equal to half of the total. For example, in the string "abccccccba", there are 2/2 = 1 'a', 2/2 = 1 'b', 6/2 = 3 'c'

So I will run from 1 to n/2, and whenever the number of each character exceeds half of the total, for example position i, it is sure that I will have to reshuffle [i, n], thus reshuffle n — i + 1 character. Then, I do a similar run from n back to n/2 + 1 to find the position i such that I have to reshuffle [1, i]

However, if I can't find such position i (for example "acbddbac"), I know I have to reshuffle at most n/2 character. To optimize the answer, I found out you don't have to reshuffle the center if it is a palindrome (I mean, in the string "acbddbac", the center "bddb" is already a palindrome, and I shouldn't reshuffle it but reshuffle the prefix "ac").

So, it's my O(n) solution, you can see my code here: https://codeforces.me/contest/2069/submission/306731691. Sorry for my bad English

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

What are Div 1 peeps doing in the official standing?

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Any solution of C without dp?

  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    I realized my code is basically the same thing as all the dp code, but I wouldn't have called it dp. I guess the dp is so simple the line is a bit blurred.
                long ways = 0;
                int ones = 0;
                int twos = 0;
     
                long totalWays = 0;
     
                for(int j = 0; j<n; j++){
                    int val = arr[j];
                    if(val == 1){
                        ones++;
                    }
                    if(val == 2){
                        ways = ways*2 + ones;
                        ways = ways % 998244353;
                    }
                    if(val == 3){
                        totalWays += ways;
                        totalWays = totalWays % 998244353;
                    }
                }
     
                out.println(totalWays);
    
  • »
    »
    19 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Yes ofcourse by precomputing powers of two and using a little maths , you can solve this without dp also , Here below is one way to do so (i don't quite know how to implement DP so i use maths as a bonus tool for myself):-

    306917242

    PLS UPVOTe...

  • »
    »
    19 месяцев назад, скрыть # ^ |
    Rev. 2  
    Проголосовать: нравится +1 Проголосовать: не нравится

    For a pair of $$$1$$$ and $$$3$$$ such that position of $$$1$$$ < position of $$$3$$$, let $$$x$$$ be the number of $$$2s$$$ between them, so the pair $$$1$$$ and $$$3$$$ contributes with $$$2^x - 1$$$ to the answer. For now, forget about the $$$-1$$$ and let the contribution be just $$$2^x$$$

    Let's iterate on the array from left to right and calculate the total contribution for each $$$3$$$ to the answer.

    Let $$$suf_i$$$ is the number of $$$2s$$$ in the suffix $$$i$$$, and $$$p(i,j)$$$ is the number of $$$2s$$$ between $$$i$$$ and $$$j$$$

    So $$$P(i,j) = suf_i - suf_j$$$

    Let the current $$$3$$$ we are calculation is at position $$$j$$$, then its contribution is $$$\sum_{i = 1, a_i = 1}^{j-1} 2^{p(i,j)} = \sum_{i = 1, a_i = 1}^{j-1} 2^{suf_i - suf_j}$$$

    Since $$$suf_j$$$ is constant for each $$$i$$$ so we can take it as common factor and the contribution will be $$$\frac{\sum_{i = 1, a_i = 1}^{j-1} 2^{suf_i}} {2^{suf_j}}$$$

    The term $$$\sum_{i = 1, a_i = 1}^{j-1} 2^{suf_i}$$$ can be updated on the fly in the loop.

    And finally, Let $$$rem$$$ be the number of pairs ($$$i$$$,$$$j$$$) such that $$$i$$$ < $$$j$$$, $$$a_i = 1$$$, $$$a_j = 3$$$, so that we can compensate all the $$$-1$$$ that we have ignored

    Check my code here: https://codeforces.me/contest/2069/submission/306743594

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +11 Проголосовать: не нравится

Is it this usual to not get delta updated in the rating for the educational rounds or is it this time that taking too much time to get updated? Anyone , is it me or everyone?

»
19 месяцев назад, скрыть # |
 
Проголосовать: нравится +14 Проголосовать: не нравится

Really great editorial on D.

Here I would like to discuss an alternative approach which is a bit more bland I guess but which I found easier to implement. (Read the editorial answer if you already haven't, it's really great.)

Basically after reducing the substring as discussed in the editorial, the answer would be a prefix or suffix. Let's say its a prefix. Then, there are two cases:

  1. The required length is <=n/2. In this case, the right half of the string decides the left half, and hence, the length of the prefix we need to shuffle is the position of the last character, where the character does not match the corresponding character of the palindrome determined by the right half. If that length is <=n/2 we have our answer.

  2. The required length is >n/2. In this case, the only necessary and sufficient condition is that the frequency of elements in the left half is >= that in the right half, and their parity is same (as the length of the string is even, and equal number of characters were removed from start and finish, so length of the reduced string is also even). This is because if the frequency is less, then the left half won't have sufficient characters to fill in corresponding places with the right half to form the palindrome. If it is more, then we can always arrange the characters with some characters in both left and the occupied right half in the prefix (this is always consistent as sum of character frequency is required length (fixed for fixed length).) The parity ensures that all characters have even final frequency, which is necessary for even length palindrome. We can perform this check using prefixes in (26*n) time.

We can repeat the similar process once again by reversing the string so as to get the shortest length for the suffix case also. Overall it's complexity is (26*n) which works pretty well under the given constraints.

Solution Link

»
18 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

I am getting TLE in problem D even though the my solution runs in $$$O(nlogn)$$$ (I think)

code

I have added comments in the code for the explanation. If someone can explain where I am making the mistake, then it would be very helpful.

Thanks

  • »
    »
    18 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    I can't think of anything that could TLE other than the lower_bound. Although it looks alright, sometimes it is O(n) (like calling std::lower_bound() over a std::set instead of using std::set::lower_bound()). If I were you, I would change that vector<array<int, 2>> to a vector<pair<int, int>>, just to test (maybe that array has something to do with a possible O(n) lower_bound?). If that doesn't solve your problem, then it has got to be some constant time optimizations (you could call reserve() on the vector "cwi" to speed things up).

    • »
      »
      »
      18 месяцев назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится

      I implemented both of the suggestions (I hope, I implemented them correctly), but it is still giving TLE verdict. solution. Also, I am confused that why lower bound on a sorted array can become $$$O(n)$$$. I would highly appreciate any help.

      • »
        »
        »
        »
        18 месяцев назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится

        About lower_bound, I said that because, for example, lower_bound over non random access iterators is O(n), and I didn't know if std::array could have something do to with that. But it seems its not the cause.

        I'm looking at your last loop, and that is literally the only remaining place where your algorithm could TLE. I see that inside the 'if' there is a 'i--'. If that runs several times, your complexity could actually not be O(nlogn). Are you sure your analysis of the time complexity is correct? (I can't help you with that now because I didn't try to solve the exercise nor understand the actual logic of your solution).

»
15 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

in problem D, is it necessary to check the suffix?

  • »
    »
    2 часа назад, скрыть # ^ |
    Rev. 3  
    Проголосовать: нравится 0 Проголосовать: не нравится

    this is only needed when our segments (pref and suff) overlap

    we need to put the characters missing from the suffix into the intersection, if we have characters that aren't in the suffix outside the overlap, we must put them into the intersection to balance things out and check if it's length of overlap is enough, otherwise, we do the same thing for the prefix, checking if there are characters missing in it, but appears in suff

»
7 месяцев назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

an O(n) solution for D: Lets first get rid of the matching prefix and suffix as mentioned in the solution. Then we need to find minm index l>=0 s.t. we can perform the operation on it(reverse the string and run the function again for operation on suffix). now we can have 2 cases for better understanding:

1) If l<n/2, then it must hold that multiset(s[0,l])=multiset(s[n-l-1,n-1]) and that the remaining substring in the middle s[l+1,n-l-2] must already be a palindrome. Thus we can find the largest palindromic substring in the middle, then check the multiset condition for the remaining prefix and suffix and get an ans from here.

2)If l>=n/2, then for a prefix [0,l] it must hold that the remaining suffix [l+1,n-1] must be derivable by some rearrangement of the prefix. So we must have the following 2 condition to be satisfied:

i) multiset(s[l+1,n-1]) must be a subset of multiset(s[0,l]) ii) In {multiset(s[0,l])-multiset(s[l+1,n-1])},i.e. remaining characters in the prefix after removing characters in the suffix, we must be able to form a palindrome in the middle, i.e. we must have freq of each remaining char to be even.

Now both checks can be done in O(n) with early breaks as soon as we find a working l. Essentially we reduce our checking function used in binary search to O(1) with smartly maintaining the multisets by simple count arrays with linear search(instead of binary) on the minm l.

Submission:https://codeforces.me/contest/2069/submission/361582752