公式

G - Lexicographically Smallest Permutation 解説 by en_translator


Hereinafter, let \(i\rightarrow P _ i\) denote the integer obtained by applying \(i\rightarrow P _ i\), \(n\ (n\geq0)\) times. Also, let \(L _ i\) be the minimum positive integer \(n\) such that \(i=P ^ n _ i\).


Consider minimizing the first element, second element, and so on.

The minimum possible value of \(A _ 1\) is the minimum value among \(A _ {P ^ n _ 1}\ (0\leq n\lt L _ 1)\). Setting \(n _ 1\) to this minimum \(n\), it turns out that \(x\equiv n _ 1\pmod{L _ 1}\) if the answer is obtained by applying the operation \(x\) times.

Subject to the condition that \(A _ 1\) takes on that minimum value, the minimum possible value is \(A _ {P ^ {n _ 1+nL _ 1} _ 2}\ (0\leq n\lt\gcd(L _ 1,L _ 2))\). Thus, one can similarly decide the answer modulo \({}\bmod{\operatorname{lcm}(L _ 1,L _ 2)}\).

Repeating this procedure, the problem can be solved.

While one cannot naively find \(L _ i\) for each \(i\) within the time limit, one can perform a bulk operation against \(P ^ n _ i\ (0\leq n\lt L _ i)\) once the answer for \(i\) has been determined.

The sample code is as follows.

Note that \(\operatorname{lcm}(L _ 1,L _ 2,\ldots,L _ i)\) can become large during the process; be careful when using a fixed-width integer type. Specifically, you may need to handle integers as large as \(2 ^ {2367}\) during the computation.

from math import gcd


N = int(input())
P = [int(x) - 1 for x in input().split()]
A = list(map(int, input().split()))

used = [False for i in range(N)]

# Based on the results so far, we know that the number of operations equals `ans` modulo `peeriod`.
period = 1
ans = 0

result = [0 for i in range(N)]

for i in range(N):
    if not used[i]:
        # Enumerate the cycle containing `i`
        cycle = [i]
        while P[cycle[-1]] != i:
            used[P[cycle[-1]]] = True
            cycle.append(P[cycle[-1]])
            
        # Minimize `A[i]`
        L = len(cycle)
        # There are `L / gcd(L, period)` choices
        choose = L // gcd(L, period)
        
        # Pick the minimum among the choices
        offset = min((A[cycle[(ans + i * period) % L]], i) for i in range(choose))[1]
        
        # Update the answer
        ans += offset * period
        period *= choose
        
        # Find the array of the answers
        for i in range(L):
            result[cycle[i]] = A[cycle[(i + ans) % L]]

print(*result)

投稿日時:
最終更新: