A2SV G5 — Round #40 (Division Deciding Contest) Editorial

Revision en3, by A2SV_Group5, 2024-08-20 11:39:09

Here is the link to the contest. All problems are from Codeforces problemset.

A. Memory and Crow

solution
code

B. Diversity

solution
code

C. Avoid Trygub

Solution

Code

input = lambda: sys.stdin.readline().rstrip() t = int(input())

for _ in range(t): N = int(input()) s = input() ans = ["b"] * s.count("b")

for char in s:
    if char != "b":
        ans.append(char)

print("".join(ans))

#### [D. Decide Your Division](https://codeforces.me/gym/543431/problem/D) <spoiler summary = "Solution"> What if the given number $$$n$$$ cannot be represented as $$$2^{cnt2}⋅3^{cnt3}⋅5^{cnt5}$$$? It means that the answer is $$$-1$$$ because all actions we can do are: remove one power of two, remove one power of three and add one power of two, and remove one power of five and add two powers of two. So if the answer is not $$$-1$$$ then it is $$$cnt2+2.cnt3+3.cnt5$$$. If this formula isn't pretty clear for you, you can just simulate the process, performing actions from third to first. </spoiler> <spoiler summary="Code">

import sys t = int(sys.stdin.readline().strip())

for _ in range(t):

n = int(sys.stdin.readline().strip())
cnt2, cnt3, cnt5 = 0, 0, 0

while n % 2 == 0:
    n //= 2
    cnt2 += 1

while n % 3 == 0:
    n //= 3
    cnt3 += 1

while n % 5 == 0:
    n //= 5
    cnt5 += 1

if n != 1:
    print(-1)
else:
    print(cnt2 + 2 * cnt3 + 3 * cnt5)
</spoiler>

#### [E. Word Transformation](https://codeforces.me/gym/543431/problem/E)

#### [F. OR Encryption](https://codeforces.me/gym/543431/problem/F)
<spoiler summary = "Hint">
Think of each bit independently.
</spoiler>
<spoiler summary = "Solution">
Solution:

Initially, we set all $$$a_i=2^{30}−1$$$ (all bits on).

You can go through every $$$i$$$,$$$j$$$ such that $$$i≠j$$$ and do $$$a_i$$$ &= $$$M_{i,j}$$$ and $$$a_j$$$ &= $$$M_{i,j}$$$.

Then we check if $$$M_{i,j}=a_i|a_j$$$ for all pairs. If this holds you found the array else the answer is $$$NO$$$.

Proof:

Initially, all elements have all their bits set on and we remove only the bits that affect our answer. If $$$M_{i,j}$$$ doesn't have a specific bit then definitely neither $$$a_i$$$ nor $$$a_j$$$ should have it. If $$$M_{i,j}$$$ has a specific bit on then we don't have to remove anything (in the end we want at least one of $$$a_i$$$ and $$$a_j$$$ to have the bit on).
</spoiler>


<spoiler summary="Code">

import sys

def solve(): n = int(sys.stdin.readline().strip()) matrix = []

for _ in range(n):
    row = list(map(int, sys.stdin.readline().strip().split()))
    matrix.append(row)

a = [2**30 - 1] * n

for i in range(n):
    for j in range(n):
        if i != j:
            a[i] &= matrix[i][j]
            a[j] &= matrix[i][j]

for i in range(n):
    for j in range(n):
        if i != j and a[i] | a[j] != matrix[i][j]:
            print("NO")
            return

print("YES")
print(*a)

t = int(sys.stdin.readline().strip())

for _ in range(t): solve() ```

G. Small Town

Solution

To solve this problem, we use binary search on the minimum possible maximum waiting time, denoted as x.

A. Binary Search on x: Perform a binary search to find the smallest x such that all customers can be assigned to three or fewer carvers with each having a maximum waiting time of x.

B. Sorting: First, sort the array of customers' pattern requests to facilitate efficient grouping.

C. Assigning Carvers: Start assigning customers to carvers from the beginning of the sorted list. For each carver, choose a range [l, r] of customers and set the optimal pattern as (r + l) // 2 to minimize the maximum waiting time. If the difference between this average pattern and the range limits exceeds x, start a new range for the next carver. Continue until all customers are assigned or more than three carvers are needed.

D. Adjust x: If three or fewer carvers suffice, reduce x to find a smaller maximum waiting time. If more than three carvers are needed, increase x and retry.

Time Complexity

The time complexity is O(n * log(m)), where n is the number of customers, and m is the difference between the maximum and minimum possible waiting times.

Code

def is_valid_waiting_time(waiting_time):
    start = nums[0]
    count = 1

    for i in range(1, n):
        if (nums[i] - start + 1) // 2 > waiting_time:
            count += 1
            start = nums[i]

    return count <= 3

l = 0
r = max(nums)

while l <= r:
    mid = (l + r) // 2
    if is_valid_waiting_time(mid):
        r = mid - 1
    else:
        l = mid + 1

print(l)

t = int(input()) for _ in range(t): solve()

</spoiler>



#### [H. Tell Directions](https://codeforces.me/gym/543431/problem/H)
<spoiler summary="Solution">
First, check the parity of $$$k$$$. If $$$k$$$ is odd, there is no solution because the cycle described in the task must have an even length. Otherwise, proceed as follows:
Use the breadth-first search (BFS) algorithm to find the shortest distance from the starting cell to all other free cells.
Next, move through the grid. Before each move, determine the next cell to go to. Consider the directions in the order $$$( &quot;D&quot;, &quot;L&quot;, &quot;R&quot;, &quot;U&quot;)$$$. The current direction is $$$c$$$. If the cell $$$x$$$ corresponding to a move in direction $$$c$$$ is empty and the distance from it to the starting cell does not exceed the remaining number of steps, then move in direction $$$c$$$, add the corresponding letter to the answer, and proceed to the next step.
If at any step it is impossible to move the Robot, a cycle of length $$$k$$$ does not exist. Otherwise, once the Robot has completed $$$k$$$ steps, simply print the answer.
</spoiler>

<spoiler summary="Code">

from collections import deque

n, m, k = map(int, input().split()) if k % 2: print("IMPOSSIBLE") exit(0)

maze = [] direc = { (1, 0): 'D', (0, -1): 'L', (0, 1): 'R', (-1, 0): 'U' } src = None for i in range(n): maze.append(input()) for j in range(m): if maze[i][j] == 'X': src = (i, j) break

bfs

track = [[float('inf') for _ in range(m)] for _ in range(n)] track[src[0]][src[1]] = 0 queue = deque([(src, 0)]) visited = set([src]) while queue: loc, step = queue.popleft() for dx, dy in direc: x, y = loc[0] + dx, loc[1] + dy if 0 <= x < n and 0 <= y < m and maze[x][y] != '*' and (x, y) not in visited: track[x][y] = min(track[x][y], step + 1) queue.append(((x, y), step + 1)) visited.add((x, y))

dfs

stack = [src] ans = [] while stack: loc = stack.pop() if len(ans) == k: print("".join(ans)) exit(0) for dx, dy in direc: x, y = loc[0] + dx, loc[1] + dy if 0 <= x < n and 0 <= y < m and track[x][y] <= k — len(ans): ans.append(direc[(dx, dy)]) stack.append((x, y)) break

print("IMPOSSIBLE")

</spoiler>


#### [I. Yet Another Pair Counting](https://codeforces.me/gym/543431/problem/I)

<spoiler summary="Hint">
Since it is counting pairs, we can use divide and conquer approach.
</spoiler>

<spoiler summary="Solution">
<p> 
Let's assume we have divided the original string in half, getting $$$substring1$$$ and $$$substring2$$$. Let's have a segment $$$(l, r)$$$
to be inverted where $$$l$$$ lies in $$$substring1$$$ and $$$r$$$ lies in $$$substring2$$$. We can now invert some suffix of $$$substring1$$$ and invert some prefix of $$$substring2$$$ and try to balance the brackets. 
</p>
<p>
There is one fact to create a balanced sequence. Because the original string is balanced:
</p>
<ul>
<li>
For $$$substring1$$$: All the closing brackets must have opening pairs. And, there could be zero or more unbalanced opening brackets.
</li>
<li>
For $$$substring2$$$: All the opening brackets must have closing pairs. And, there could zero or more unbalanced closing brackets.
</li>
</ul>
<p>
For instance, after some inversion, if we have $$$Y$$$ amount opening brackets that didn't get a 
closing match in the fist substring, we should find $$$Y$$$ amount of excess closing brackets in the second substring. 
</p>
<p>
Now, with the same logic we can further divide the two substrings, and account for every $$$(l, r)$$$ pair.
</p>
<p>
Let's divide $$$substring1$$$ into halves, $$$a$$$ and $$$b$$$. After some $$$(l, r)$$$ inversion, where $$$l$$$ lies in $$$a$$$ and $$$r$$$ lies in $$$b$$$, let's say we have $$$X$$$ amount of excess opening brackets in $$$a$$$, the $$$X$$$ closing matches could come from not just $$$b$$$, but the whole suffix starting from and including $$$b$$$. The same applies if we have some subsegment before $$$a$$$. So, to handle that case, we do some preprocessing and count excess prefix openings and excess suffix closings.   
</p>

<p>
Time complexity: $$$nlog(n)$$$ <br/>
Make sure to use $$$PyPy 3-64$$$.
</p>

</spoiler>

<spoiler summary="Code">

import sys from collections import defaultdict input = lambda: sys.stdin.readline().rstrip()

def conquer(l1, r1, l2, r2):

excess_opening = defaultdict(int)
inverted_open = 0
unpaired_closing = 0
# all closing brackets must have an opening pair on the left subarray
# invert some suffix of substring 1
for indx in range(r1, l1 - 1, -1):
    if s[indx] == ')':
        inverted_open += 1
        # follow kadan's algorithm to find opening matches for the closings
        # if we have an excess opening, it is no use for a closing that comes before it
        # so we don't make the unpaired_closing negative
        unpaired_closing = max(unpaired_closing - 1, 0) 

    else:
        unpaired_closing += 1
        inverted_open -= 1

    # uninverted prefix of this index must provide opening pairs for the unpaired closings
    if pref[indx - 1] >= unpaired_closing:
        excess_opening[pref[indx - 1] + inverted_open] += 1


unpaired_opening = 0
inverted_close = 0
count = 0 # (l, r) matches 

# invert some prefix of substring 2
for indx in range(l2, r2 + 1):
    if s[indx] == '(':
        inverted_close += 1
        unpaired_opening = max(unpaired_opening - 1, 0)

    else:
        unpaired_opening += 1
        inverted_close -= 1

    # uninverted suffix of this index must provide closing pairs for the unpaired openings
    if suf[indx + 1] >= unpaired_opening:
        # match 'y' amount of excess opening in the first substring
        # with 'y' amount of closing in the second substring
        count += excess_opening[suf[indx + 1] + inverted_close]

return count

def divide(l, r): if l >= r: return 0

mid = (r + l)//2
left_count = divide(l, mid)
right_count = divide(mid + 1, r)
cur_count = conquer(l, mid, mid + 1, r)
return left_count + right_count + cur_count

t = int(input()) for _ in range(t): s = input() n = len(s)

pref = [0]*(n + 1)
suf = [0]*(n + 1)

openning_pref = 0
closing_suf = 0
for i in range(n):
    openning_pref += 1 if s[i] == '(' else -1
    closing_suf += 1 if s[n - i - 1] == ')' else -1

    pref[i] = openning_pref
    suf[n - i - 1] = closing_suf

ans = divide(0, n - 1)
print(ans)

```

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en8 English A2SV_Group5 2024-08-20 14:04:38 0 (published)
en7 English A2SV_Group5 2024-08-20 11:54:48 3 Tiny change: 'ere could zero or m' -> 'ere could be zero or m'
en6 English A2SV_Group5 2024-08-20 11:50:16 18
en5 English A2SV_Group5 2024-08-20 11:46:24 1776
en4 English A2SV_Group5 2024-08-20 11:44:34 20 Tiny change: 'n\n\n```\n\n#### [D.' -> 'n\n\n```\n</spoiler>\n#### [D.'
en3 English A2SV_Group5 2024-08-20 11:39:09 9823
en2 English A2SV_Group5 2024-08-20 11:03:55 4314
en1 English A2SV_Group5 2024-08-20 11:02:34 894 Initial revision (saved to drafts)