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

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

1895A - Сундук с сокровищами

Идея: BledDest

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

1895B - Точки и минимальное расстояние

Идея: fcspartakm

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

1895C - Порванный счастливый билет

Идея: BledDest

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

1895D - XOR-конструктив

Идея: AcidWrongGod

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

1895E - Бесконечная карточная игра

Идея: BledDest

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

1895F - Красивые массивы

Идея: Neon

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

1895G - Два символа, два цвета

Идея: BledDest

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

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

ok

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

problems C and D were excellent

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

For problem D it is possible to find b1 bit by bit. Calculate the amount of ones in i-th bit of all b-th if b1_i = 1 and compare with the amount of 1th for numbers from 0 to n-1. If they are different b1_i=0

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

    Yes, this is author's solution)

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

    This was really nice idea. Thanks

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

    I thought of the following logic but I feel it is more efficient as I do not require to calculate 1's from 0 to (n-1):

    The following function 'calc' return the first element b[0] of the sequence.

    It takes input 's', which is equivalent to 'c' in the editorial:

    (defined as: s[0] = 0 ; s[i] = s[i-1] ^ a[i-1] ;)

    The code is written in Python.

    BITS = 32
    def calc(s):
        """
        Logic: (Applicable for all 'n' and 'a' for which atleast one valid solution exists)
        NOTE: 'b' can be obtained by XORing 's' by some appropriate value.
    
            If at a bit position in 's', the count of '0' is more then, 
            the corresponding bit position in all elements of 's' will 
            be XORed with '0'. (Hence, effectively it is unchanged)
    
            If at a bit position in 's', the count of '1' is more then, 
            the corresponding bit position in all elements of 's' will 
            be XORed with '1'. (Hence, effectively it is "flipped")
    
            Otherwise, if both '0' and '1' count are equal at a bit position 
            of 's', the bit position may be arbbitrarily chosen to be either 
            flipped or kept unchanged for all elements.
        """
        global BITS
    
        res = 0
        for i in range(BITS):
            count = [0, 0]
            for j in range(len(s)):
                count[(s[j]>>i) & 1] += 1
            res += (count[0]<count[1])<<i
        
        return res
    
  • »
    »
    2 года назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    how does your solution ensure that the largest b[i] is less than n?

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

      Since there is a solution and the constructed one satisfies all an-s.

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

      Consider the possible solutions for some given 'n'. (In Binary Notation)

      It follows from one constraint that, if 'v' is a solution, then all solutions satisfying that constraint may be obtained by simply complementing(~) all elements of 'v' at some 0 or more bit-positions.

      ('c' defined as : c[0] = 0 ; c[i] = c[i-1] ^ a[i-1] ; is also a solution to this constraint)

      Now, as per the other constraint 'v' must also be a permutation of {0, ..., n-1}

      Let us try to find a path to reach this solution that satisfies both, starting from 'c'.

      Properties of the goal that we are trying to reach:

      As our goal is a permutation of {0, ..., n-1}, properties of permutations of {0, ..., n-1} apply to our goal

      The i'th bit position will have as many 1's as present in the i'th bit from 0 to n-1.

      The i'th bit position will always have equal or more 0's than 1's (shown by mcclane57)

      Now, it turns out that satisfaction of these two properties suffice to reach our goal, assuming that it exists. My program simply tries to satisfy the above 2 properties.

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

    The above solution will only work for even length right? For odd length, you'll have to simply find b1 I guess.

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

    231233772. Is this what u talking about.. If Yes can u explain what does the portion bit1[i] != bit2[i] mean ?

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

    But if when b1_i = 1 and when b1_i = 0, the amout of ones are both equal to the amout of ones for numbers from 0 to n-1, you cannot exclude one of them. So how to prove that b1_i = 0 and b1_i = 1 are both right?

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

Plz someone explain bit by bit solution for problem D. And also explain properly! (Not Editorial solution)

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

    Sure. The same as in editorial we want to understand the value of b1, then b2 = b1^a1, b3 = b2^a2 and so on. Since XOR is a bitwise operation we can solve this problem bit by bit. For i-th bit of b1 there are two possible cases b1_i = 0 or b1_i = 1. By calculating explicitly b2_i, b3_i ... bn_i we can count the amount of 1 among these values. If the bit is set correctly for b1 then the amount will be equal to amount of numbers from 0 to n-1 with nonzero i-th bit (if amount of 1th equal to amount of 0th then any value of this bit will lead to the solution). The complexity is O(32n) while using bitset<32> to go from int to bits and reverse.

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

It is sad that I was almost 1 hour solving problem D with operator OR (always have a problem where I failed to "read" the problem) and had no time for problem E but C-E are nice problems for educational.

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

Plz explain me problem C why suml — sumr>0 made Lucky Ticket,thanks.

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

    Check my implementation, it feels a bit simpler to me with similar idea.

    Let's say we are checking 52349. Split it at every digit and try as left and right part of ticket:

             52349 | anything with length 5, sum 23 (5,23)
             5234 | 9 + (3,14)
             523 | 49 + (1, 5)
     (1,9) + 52 | 349
    (3,13) + 5 | 2349
    
»
2 года назад, скрыть # |
 
Проголосовать: нравится +79 Проголосовать: не нравится

Problem D is solvable in linear time (ignoring IO) in the word RAM model.

I'll show an alternate $$$O(n \log n)$$$ solution, and then show how to optimize it.

Notice that among the numbers from $$$0$$$ to $$$n-1$$$, $$$\left \lfloor\frac{n}{2}\right\rfloor$$$ numbers are odd, and the rest are even.

If $$$n$$$ is odd, these two counts are different, so we can use it to determine whether the first number of $$$b$$$ should be odd or even. Make it even if the count is already correct, and odd if we need to correct the count.

If $$$n$$$ is even, toggling the $$$0$$$-th bit in each number is a bijection from the list onto itself, so it doesn't matter whether we set the bit in the first number of $$$b$$$.

A similar argument can be made for each of the other bit positions, but the formula for the expected count is a bit more complicated. The expected number of $$$1$$$-bits in the $$$j$$$-th bit position is $$$n - \left \lfloor\frac{n}{2^{j+1}}\right\rfloor \cdot 2^j - \min\left(n \bmod 2^{j+1}, 2^j\right)$$$

So now we have a way to construct the answer given the number of $$$1$$$-bits seen in each bit position. Counting this in $$$O(n \log n)$$$ time is easy, but doing it in $$$O(n)$$$ is also possible, using bitset. I learned this trick from simonlindholm's "troll" subtask in the problem ligatures.

The idea is that when incrementing a counter, we very rarely need to carry. It takes $$$2^j$$$ increments before we increment the $$$j$$$-th bit, so the total number of carries when incrementing a number $$$n$$$ times starting from $$$0$$$ is $$$\frac{n}{1} + \frac{n}{2} + \frac{n}{4} + \dots \in O(n)$$$

In code it looks something like this:

void increment(std::span<bool> bits) {
  bool carry = true;
  for (bool &b : bits) {
    bool next_carry = carry & b;
    b ^= carry;
    carry = next_carry;
    if (!carry) break; // this early exit is what makes it amortized O(n)
  }
}

So for a single counter, we can implement the counting in linear time while operating on just $$$O(1)$$$ bits at a time. But in the word RAM model, we can operate on $$$\Omega(\log n)$$$ bits at a time. We'll use this to run several counters in parallel. For each bit-position in the counter, instead of storing a single bit, we store a bitset, and then the increment function takes a mask of which of the counters to increment:

void increment(std::span<std::bitset<20>> bits, std::bitset<20> carry) {
  for (auto &b : bits) {
    auto next_carry = carry & b;
    b ^= carry;
    carry = next_carry;
    if (carry.none()) break;
  }
}

But modifying the code like this broke the amortization argument. Different counters may need to carry at different times. The trick to fix this is to somehow synchronize the carrying by allowing different representations of the same number inside the counters. Instead of letting each digit in the binary representation be $$$0$$$ or $$$1$$$, we let it be $$$0$$$, $$$1$$$, or $$$2$$$. It's still base $$$2$$$, it's just that digits are allowed to be a little too big. It can also be seen as storing the carry bit as a lazy update. To do this, we store a pair of bitmasks for each bit position:

void increment(std::span<std::pair<std::bitset<20>, std::bitset<20>> bits, std::bitset<20> carry) {
  for (auto &[lo, hi] : bits) {
    assert((lo & hi).none()); // invariant: we have only 0, 1, or 2 as the digit, not 3
    hi |= carry & lo;
    lo ^= carry;
    if (we_dont_bother_carrying_further()) break;
    carry = hi;
    hi.reset();
  }
}

Now if we pick an appropriate condition for not bothering to carry further, we can both maintain the digit-invariant and achieve $$$O(n)$$$ complexity. In case the $$$0$$$-th digit becomes $$$2$$$ after $$$2$$$ steps, we need to carry in the $$$3$$$-rd step. After that the $$$0$$$-th digit is either $$$0$$$ or $$$1$$$. From then on, we need to carry from the $$$0$$$-th digit every $$$2$$$-nd step. For simplicity, we can ignore the $$$2$$$ carry-less increments at the start, and just always carry from the $$$0$$$-th digit every other step. Similar arguments can show that we need to carry from the $$$i$$$-th digit every $$$2^i$$$-th step. How many steps we need to carry turns out to be the number of trailing zeros in the number of steps we have completed so far.

Here's an implementation: 231387717

Note that this is not the most efficient parallel bit-counter. You might get better performance by doing this trick in base $$$4$$$ instead, and with some extra care, you can let the digits go further past their usual allowed range.

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

In problem D, how bit by bit logic is working in below case cause even after bit flips the count of set bits at 2nd bit are unequal in b.

n=6, a= 1 6 1 4 7, b= 0 1 7 6 2 5(calculated prefix xor of a if b starts with 0)

output: is not in range of 0-5 but it exceeded for above test case

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

Trie is a more standard way to solve D, I like it better!

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

Can someone explain the trie solution ? how the trie is constructed, and how are they finding max b_1^c_i

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

    Okay so since b2 = a1 ^ b1, b3 = a1 ^ a2 ^ b1, ..., bn = a1 ^ ... ^ an-1 ^ b1.

    From this fact you can observe that finding b1 will automatically result in finding all the other values.

    So start by forming a Trie which contains pointer to a bit array of size [2] (for each bit 0\1. Now since all you need to check is that MAX(b1 ^ pref[i]) < N insert all the pref values inside the trie bit by bit. After inserting these values enumerate for each b1 in the range [0, N).

    Now how do you find MAX(b1^pref[i]) in LOG(N) well since XOR is only one for two non-similar bits. Start iterating for each bit and checking if the trie has a bit opposite to the set bit in the b1 you are checking, if this is true then choose that path and descend the trie else move forward.

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

      A basic Trie that does the job.

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

Problem D can be solved by just counting the number of 0 and 1 bits at each position and comparing with the expected count for the sequence $$$[0, \ldots, n-1]$$$. If at some position the count is wrong, we must flip that bit. 231908591

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

Problem D :

!!Read first solution from the comment box.

There is a proof or simple observations that if n==(2^k) then anything is possible as b1. But when n!=(2^k) then the number of open and close form of a particular bit are not same , in this case we can take decision . But some bits open and close forms number are same ,in this case first observation works.

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

D:this is a good question, i love it

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

I solved $$$D$$$ with binary search

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

How binary trie will be used like count of 0 > count of 1 was sufficient

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

If n is a power of two, choosing b1=0 always works. Otherwise, we construct bit by bit. For each bit position s, we compare the number of ones and zeros in the s-th bit among all values of c. If ones are more than zeros, we set the s-th bit of b1 to 1. otherwise, we set it to 0. https://mirror.codeforces.com/contest/1895/submission/355909410

Consider the case n = 2^k. The statement guarantees that at least one valid array exists, so for each bit position s, there is some choice of the s-th bit of b1 that produces a permutation of {00...11...00...11...}.

Suppose that setting the s-th bit of b1 to 0 works. Then the values c (and b1) can be reordered so that their s-th bits form the pattern 00...11...00...11..., with blocks of size 2^s. Inside each block, the lower bits (s-1), (s-2), ... also follow the same regular alternating structure.

Now change the s-th bit of b1 to 1. This only flips the s-th bit of every value, so the pattern becomes 11...00...11...00.... The structure of all lower bits stays exactly the same. Therefore, by simply reordering the blocks, we can restore the pattern 00...11...00...11....

Therefore, when n = 2^k, the s-th bit of b1 can be chosen arbitrarily (in particular, b1 = 0 always works).

When n is not a power of two, the symmetry of the bit structure is broken, so the choice of each bit of b1 is no longer arbitrary.

Fix a bit position s, and consider the array c. Let ones be the number of elements whose s-th bit is 1, and zeros be the number of elements whose s-th bit is 0.

The target permutation {0, 1, ..., n-1}, when viewed at the s-th bit, always has the form 00...11...00...11.... In particular, this implies that the number of ones cannot exceed the number of zeros.

If ones > zeros, then no reordering of the array can produce the required pattern 00...11...00...11.... Therefore, we must flip the s-th bit of all elements, i.e. swap ones and zeros. This is achieved by setting the s-th bit of b1 to 1.

If ones <= zeros, setting the bit to 1 would make ones > zeros. Hence, the s-th bit of b1 must be 0.

Thus, for each bit position s, the value of the s-th bit of b1 is uniquely determined. Applying this rule independently for all bits fully determines b1.

I apologize if my explanation is unclear or contains any mistakes.