公式

C - Remove and Append 解説 by vwxyz


原案:vwxyz

一度も削除されない値はすべて最終的な \(P\) の先頭にそのままの順番で残ります。
長さ \(N\) の配列を用意してすべての要素を \(0\) にしておき、\(q=1,2,\dots,Q\) について \(a_q\) 番目の要素を \(1\) にするなどの処理により、\(1,2,\dots,N\) が操作対象になるかどうかを \(O(N)\) で判定できます。
\(P\) の各要素で一度も操作対象にならないものを並べることで、この部分は \(O(N)\) で求めることができます。

次に、操作対象となる要素の順番について考えます。
操作によってある要素を \(P\) の末尾に追加しても、その要素が後の操作でまた削除される可能性もあるため、愚直に処理することができません。
逆に、その要素が対象となる最後の操作以降は、それが \(P\) から削除されることはありません。
このような場合には、操作を逆順に見るというテクニックが有効になることがあり、この問題もこれにより解くことができます。
空配列 \(P'\) を用意しておきます。
\(q=Q,Q-1,\dots,1\) の順に、\(a_q\) が逆順に見て初めて出てくる(もとの操作順で見れば、\(a_q\) が操作対象となる最後の)操作ならば、\(P'\) の先頭に \(a_q\) を追加します。
\(p=1,2,\dots,N\) について、\(P\) が出てきたかどうかのフラグを持っておくことで、この処理は \(O(N)\) でできます。 こうしてできた \(P'\) は、最終的な \(P\) において操作対象となる要素を取り出したものになっており、これを先ほどの \(P\) の末尾に連結させたものが求めるものです。

\(P_1,P_2,\dots,P_N\) に対して操作をした後に \(a_1,a_2,\dots,a_Q\) に対して操作をすると解釈するとすべての要素が一度は操作対象となるため、解説に書かれている前半の処理を省くことができます。

投稿日時:
最終更新: