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)
投稿日時:
最終更新: