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

Автор BledDest, история, 2 года назад, перевод, По-русски

1913A - Увеличение рейтинга

Идея: Roms, подготовка: awoo

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

1913B - Обмен и удаление

Идея: BledDest, подготовка: adedalic

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

1913C - Игра с мультимножеством

Идея: Ferume, подготовка: Ferume

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

1913D - Схлопывание массива

Идея: Roms, подготовка: Roms

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

1913E - Задача про матрицу

Идея: Ferume, подготовка: Ferume

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

1913F - Палиндромы и изменения

Идея: Ferume, подготовка: Ferume

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

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

Is it normal that in the solution of problem D the first larger element on the left is searched for, although in the author's solution it is the first smaller element?

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

good D

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

in problem B in 4th case, where s=111100 we can delete first 2 1's in cost 2 and we can swap rest of the 0's and 1's, it will cost only 2 but author is calculating for cost 4.

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

I created video editorial for D: Array Collapse.

I also created some practice problems on the prerequisites for this problem (Montonic Stacks + DP), details of which can be found here.

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

Can anyone please explain how to arrive at the formula: no. of operations = sum_matrix — res.first + res.second?

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

In promble E:

add a directed edge from C_j to T with capacity A_i and cost 0.

Why is the capacity A_i instead of B_j?

»
2 года назад, скрыть # |
Rev. 2  
Проголосовать: нравится +32 Проголосовать: не нравится

Alternative solution for problem D:

We can break down the problem recursively. If we look at some range [l,r] of the array, let the index of the minimum element of a[l...r] to be idx, we can notice that the ranges [l,idx-1] and [idx+1,r] are independent, because no matter what operations we do (in [l,r]), the element at position idx will never be erased, so it acts like a wall between the left part and the right part.

Then, we can define solve(l,r) as the answer for a [l,r], and compute it by calculating solve(l,idx-1)*solve(idx+1,r).

One more detail is that when we are looking at [l,r], we need to know if the minimum element above us (from the previous recursion) is to the right or to the left (or both), because when this happens we can erase any suffix/prefix in [l,r], including the minimum element, so we have to add in our answer to [l,r] the answer to [l,idx-1] or to [idx+1,r] (or both). We do that with a 2 bits mask.

Code snippet:

ll solve(int l, int r, int dir) {
    if (l > r) return 1;
    auto [val, id] = st.query(l, r);
    ll L = solve(l, id - 1, dir | 1);
    ll R = solve(id + 1, r, dir | 2);
    ll ret = L * R % mod;
    if (dir & 1) ret = (ret + L) % mod;
    if (dir & 2) ret = (ret + R) % mod;
    if (dir == 3) ret = (ret - 1 + mod) % mod;
    return ret;
}

Obs: if the previous minimums comes from both left and right (i.e. the mask is equals to 3), we subtract 1 from the current answer because we counted the empty array twice.

This solution works in O(n log(n)) because of the sparse table build.

Full code: 238167605

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

    Understood the recursive spliting part. Now trying to process remaining parts. [The above explanation should be added in the editorial]

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

    Can you explain your code a little bit like how you are Calculating ret variable

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

      Omg I've accidentally deleted my answer :P, I'll type it again

      Imagine this testcase: 10 4 2 5 3 6 1 9 7 8

      The important thing to note is that subarrays to the left and to the right of element 1 are independent, so I just calculate the answer for them and multiply those values.

      [10 4 2 5 3 6] is L

      [9 7 8] is R

      Let's look at L: [10 4 2 5 3 6]

      You agree with me that I can't arbitrary erase the 10 in the beginning? But I do can arbitrary erase the 6 at the end, because there is a 1 on the right of it. In fact, I can erase any suffix of the subarray [10 4 2 5 3 6].

      When I split this [10 4 2 5 3 6] into [10 4] 2 [5 3 6], and look at [5 3 6], now I can erase both the beginning and the end of this subarray, because to the left of it we have the 2, and to the right of it we have the 1.

      The variable dir is a bitmask that tells me this, if there is a previous minimum element to the left or right of my current range. If there is some, I need to sum in my ret variable the value of L or R (or both).

      If there is both a left and a right minimum element (i. e. the mask is 3), I subtract 1 from the ret variable because in this case I counted the empty subarray twice.

      I'm sorry if it's still confusing, but feel free to ask more.

      Take a look at the full code to see if it clears out a little bit: 238167605

      There is also this submission 237782371 from Ayalla which is very similar but with some slightly difference on the base case of the recursion and in the calculation of variable ans (he doesn't need to subtract 1 from ans when mask is equals to 3), it may be more intuitive this way.

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

        I still don't get why you add L or R if there is a previous minimum element

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

          Imagine you have some array [3 4 2 1 5 6], obviously $$$1$$$ is the minimum element, so we can break into L = solve([3 4 2]) and R = solve([5 6]), alright? I can't erase any prefix/suffix of this array, because there's no one in the left or right of my array to erase it.

          But, if I'm recursively going down and at some point I look at something like this:

          ... 1 ... [3 5 2 8] ...

          I mean, I'm looking to the range between values $$$3$$$ and $$$8$$$, but I have a $$$1$$$ in my left (which was a minimum element from previous recursions, and I know it exists by looking at the variable $$$dir$$$)

          When I'm computing the answer to the subarray [3 5 2 8], I'll break it in 2 parts splitting in the minimum element and multiplying those L and R values, this will count the number of reachable subarrays that contains my current minimum element (which happens to be 2). But, as I have a previous minimum element on my left, I need to count the number of subarrays that don't contains my current minimum element. I need to count this because I can erase any prefix of my current subarray (with the previous minimum element) and delete my current minimum, so I add variable R to my current answer.

          Is that clear? I know that it's kinda tricky to fully understand this solution

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

    upd:nevermind, I am wrong

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

I debug D for hours just to realize i forget to change the mod value -_-

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

For Problem D, can someone explain what is meant by this? It is easy to see that it is enough for all these elements to be smaller than the fixed one. Then they can be removed one by one from left to right. If there is at least one larger element, then the maximum of such elements cannot be removed. But the problem statement says that you can choose a contiguous subsegment of p and remove all elements from that subsegment, **except** for the minimum element on that subsegment. So my interpretation would be that it the condition should be that all of the elements be larger than the fixed one? Since the fixed one is the minimum, we can always remove the element adjacent to it. And if there is a smaller element, then we can't remove that element. I don't understand the usage of maximum and minimum in the tutorial and in my interpretation they are reversed.

e.g. Let 1 be fixed in 1 2 3 4 5 6. 1 is the minimum element, so the elements after it are larger and can be removed one-by-one. I am interpreting the tutorial as saying the opposite?

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

An alternate editorial for Problem D

Let us define:

  • $$$dp[i] =$$$ The number of reachable arrays for prefix of length $$$i$$$ such that we keep the $$$i$$$-th element
  • $$$res[i] =$$$ The number of reachable arrays for prefix of length $$$i$$$

The answer that we are looking for is $$$res[n]$$$.

Let $$$L[i]$$$ be the largest integer such that $$$p[L[i]] \lt p[i]$$$ and $$$L[i] \lt i$$$, then we will have the following transitions.


If $$$L[i]$$$ does not exist, i.e. $$$p[i]$$$ is the smallest in the prefix of length $$$i$$$ then:

  • $$$\displaystyle dp[i] = 1 + \sum_{k=1}^{i-1} dp[k]$$$
  • $$$res[i]=dp[i]$$$
Explanation

If $$$L[i]$$$ exist, then:

  • $$$\displaystyle dp[i] = res[L[i]] + \sum_{k=L[i]+1}^{i-1} dp[k]$$$
  • $$$res[i] = res[L[i]] + dp[i]$$$
Explanation

We can use monotonic stack and prefix sums for the transitions.

Here is my submission.

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

You can also optimize DP in D with RURQ.

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

I found by far easier to understand C solution by ordering the weights in non-ascending order instead. I found really confusing to follow the explanation with non-descending order, is anyone able to share a more detailed explanation of how it works? would be really appreciated!

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

1913B - Swap and Delete Why in the sample test case 111100 have output 4 and not 2? Please explain.

Like we can swap two 1's from two 0's and delete rest of 1's and the operation cost will be 2 only. Example:- 111100(in input). - delete first two 1's. String will be 1100 and cost will be 2. - swap the rest 1's with 0's. cost 0 and total cost will remains 2. - Now the string s = 1100 and t=0011.

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

    The problem statement says: "Note that you are comparing the resulting string $$$t$$$ with the initial string $$$s$$$." So in your case, $$$s$$$ does not change and remains $$$111100$$$.

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

An alternate solution for C: 321746737

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

problem b made me lose my braincells