公式

A - Good Permutation 2 解説 by potato167


\(A\)\(1\) もしくは \(N\) が含まれているときは良い順列は存在しません。

逆に \(A\)\(1\)\(N\) がどちらも含まれていないときは良い順列が存在します。このときを考えます。

例えば \(P = (1 ,N, N - 1, N - 2, \dots, 3, 2)\) とすると、\(1, 2\) どちらも含む \(P\) の連続部分列は \(P\) 自身しか存在しないため、\(P\)良い順列となります。

以上のように \(P_{1} = 1\) となる良い順列が存在するため、辞書順最小の良い順列\(P_{1} = 1\) となります。このとき、任意の整数 \(x\) に対して、\(P\) の連続部分列で \((1, 2, \dots , x)\) の順列であるものが存在するなら \((P_{1}, P_{2}, \dots , P_{x})\) に限ります。

\(i=1\) を除く \(P_{i}\)\(i\) の小さい順に決めていきます。ここで、\(P_{i}\) を決めるときに、\(P_{1},P_{2},\dots P_{i - 1}\) は全て \(i\) 以下の数であることを満たしているとします。また、\(P_{1}, P_{2}, \dots P_{i - 1}\) に含まれていない \(i\) 以下の数を \(a\) とします。

\(A\)\(i\) が含まれているとき

辞書順最小にするために、\(P_{i} = a\) とすると、良い順列でなくなるため、\(P_{i}=i+1\) とします。\(P_{i}\)\(i+1\) 以下であるため、\(P_{1}, P_{2}, \dots P_{i}\) は全て \(i+1\) 以下の数になります。また、\(a\) は変化しません。

\(A\)\(i\) が含まれていないとき

辞書順最小にするため、\(P_{i} = a\) とします。この数は \(i\) 以下の数であるため、\(P_{1}, P_{2}, \dots P_{i}\) は全て \(i+1\) 以下の数になります。また、\(a\)\(i+1\) になります。

よって、以上を実装すれば良いです。計算量は \(O(N)\) です。

# input
N, M = map(int, input().split())
A = list(map(int, input().split()))
ban = [0] * N
for a in A:
    # 1-index  -> 0-index
    ban[a - 1] = 1;

# impossible
if ban[0] or ban[N - 1]:
    print(-1)
    quit()

# init
P = [0] * N
P[0] = 1
a = 2

# calc
for i in range(1, N):
    if ban[i] == 1:
        P[i] = i + 2
    else:
        P[i] = a
        a = i + 2

# output
print(*P)

また、以下のようにしても構築できます。

\(P = (1, 2, \dots ,N)\) と初期化した後、 \(i = 2, 3, \dots ,N - 1\) の順に、以下の操作をする。

  • \(A\)\(i\) が含まれているなら、\(\text{swap}(P_{i},P_{i + 1})\) をする。

c++ による実装例

投稿日時:
最終更新: