Official

B - 整列の部分修正 / Partial Correction of a Sorted Sequence Editorial by admin

gpt-5.5-high

概要

現在の順列 \(p\) の連続区間をちょうど \(1\) 回反転して、目標の順列 \(q\) にできるか判定します。
ポイントは、\(q\) の各要素が \(p\) のどの位置にあったかを見ることです。

考察

\(p\) の各値がどの位置にあるかを記録しておきます。
つまり、

\[ \mathrm{pos}[x] = p \text{ における } x \text{ の位置} \]

とします。

そして、\(q_i\)\(p\) のどの位置にあったかを

\[ a_i = \mathrm{pos}[q_i] \]

とします。

例えば、

\[ p = [1, 2, 3, 4, 5, 6] \]

で、区間 \([2, 5]\) を反転すると、

\[ q = [1, 5, 4, 3, 2, 6] \]

になります。

このとき、\(q\) の各要素がもともと \(p\) の何番目にあったかを見ると、

\[ a = [1, 5, 4, 3, 2, 6] \]

です。

つまり、反転していない部分では \(a_i = i\) となり、反転した区間では位置が逆順になります。

区間 \([L, R]\) を反転した場合、次が成り立ちます。

  • \(i < L\) または \(i > R\) の位置では変化しないので、\(a_i = i\)
  • \(L \leq i \leq R\) の位置では反転するので、\(a_i = L + R - i\)

したがって、\(a_i\)

そのまま / 連続した逆順区間 / そのまま

という形になっている必要があります。

素朴な方法が遅い理由

すべての区間 \([L, R]\) を試すと、区間の選び方は \(O(N^2)\) 通りあります。
さらに各区間について実際に反転後の配列を比較すると \(O(N)\) かかるため、全体で \(O(N^3)\) になってしまいます。

\(N \leq 10^6\) なので、この方法では間に合いません。

重要な気づき

最初に \(a_i \neq i\) となる位置を見つけたとします。
この位置は、反転区間の左端 \(L\) でなければなりません。

また、そのとき

\[ a_L = R \]

です。

なぜなら、反転後の位置 \(L\) には、もともと位置 \(R\) にいた要素が来るからです。

つまり、最初のズレを見つけた時点で、反転区間 \([L, R]\) は一意に決まります。
あとは、その区間内が正しく逆順になっているか、区間外がそのままかを確認すればよいです。

アルゴリズム

まず、\(p\) の各値の位置を記録します。

pos[p_i] = i

ただし、実装では \(0\) 始まりの添字を使っています。

次に、\(q\) を左から見ていきます。

各位置 \(i\) について、

a = pos[q_i]

を計算します。

まだ反転区間を見つけていない場合:

  • \(a = i\) なら、その位置は一致しているのでそのまま進みます。
  • \(a \neq i\) なら、ここが反転区間の左端 \(l\) です。
    • 右端は \(r = a\) と決まります。
    • このとき \(r \leq l\) なら不可能です。

反転区間を見つけた後:

  • \(i \leq r\) の間は、反転区間の中です。
    • 正しく反転されているなら、

\[ a = l + r - i \]

でなければなりません。

  • \(i > r\) なら、反転区間の外です。
    • そのため、

\[ a = i \]

でなければなりません。

最後まで条件を満たせば Yes、途中で条件を満たさなければ No です。

なお、最初から \(p = q\) の場合も Yes です。
問題では \(L = R\) の反転、つまり何も変化しない操作も許されているためです。

計算量

  • 時間計算量: \(O(N)\)
  • 空間計算量: \(O(N)\)

実装のポイント

\(N\) が最大 \(10^6\) と大きいので、高速な入力処理を使っています。

また、\(q\) 全体を配列として保存する必要はありません。
\(q_i\) を読みながら、その場で pos[q_i] を確認して判定しています。

コード中では \(0\) 始まりの添字を使っているため、反転区間内の条件は

a == l + r - i

となります。

ソースコード

import sys

def main():
    data = sys.stdin.buffer.read() + b' '
    idx = 0

    def next_int():
        nonlocal idx
        while data[idx] <= 32:
            idx += 1
        x = 0
        while data[idx] > 32:
            x = x * 10 + data[idx] - 48
            idx += 1
        return x

    n = next_int()

    pos = [0] * (n + 1)
    for i in range(n):
        pos[next_int()] = i

    l = -1
    r = -1
    ok = True

    for i in range(n):
        a = pos[next_int()]

        if l == -1:
            if a != i:
                l = i
                r = a
                if r <= l:
                    ok = False
                    break
        elif i <= r:
            if a != l + r - i:
                ok = False
                break
        else:
            if a != i:
                ok = False
                break

    print("Yes" if ok else "No")

if __name__ == "__main__":
    main()

この解説は gpt-5.5-high によって生成されました。

posted:
last update: