Official

E - Lining Up 2 Editorial by MMNMM


次のような数列 \((B _ i) _ {1\leq i\leq N}\) を考えます。

\[B _ i=\left\lbrace\begin{matrix}j&(A _ j=i)\hphantom{\text{otherwise}}\\-1&(\text{otherwise})\hphantom{A _ j=i}\end{matrix}\right.\]

これは、「人 \(i\) の直後の人は人 \(B _ i\)(ただし、存在しなければ \(-1\))」を満たす数列です。

この \((B _ i) _ {1\leq i\leq N}\) が求められれば、\(A _ x=-1\) を満たす \(x\) を用いて、列の並びを人 \(x,\) 人 \(B _ x,\) 人 \(B _ {B _ x},\) 人 \(B _ {B _ {B _ x}},\ldots,\) 人 \(B _ {B _ {{}_{\ddots _ {B _ x}}}}\) と書くことができます。

よって、数列 \((B _ i)\) と先頭の人を求めて \(x\leftarrow B _ x\) を適切に繰り返せばよいです。

実装例は以下のようになります。 直後の人が存在しないときの \(B _ i\) の値は(存在するときの値とかぶらない範囲で)自由に定めてよいことを利用しています。

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    unsigned N;
    cin >> N;

    vector<unsigned> B(N, N); // B[i] := 人 i の直後の人(いなければ N)
    unsigned front;

    for(unsigned i = 0; i < N; ++i){
        int A;
        cin >> A;
        --A; // 0-indexed に直しておく
        if(A < 0)
            front = i;
        else
            B[A] = i; // 人 i の直前が人 A ⇔ 人 A の直後が人 i
    }

    while(front < N){ // N になるまで(= 直後の人がいなくなるまで)直後に移動を繰り返す
        cout << front + 1 << " ";
        front = B[front];
    }
    cout << endl;

    return 0;
}

posted:
last update: