AtCoder Grand Contest 038 B - Sorting a Segment
公式解説と少し違う方法で解いたので記録。
解法
ある長さ の区間を昇順に並び替えた時に、値が変更される最左のインデックスを 、最右のインデックスを とします。この時操作の結果は、閉区間 内の要素を昇順に並び替えたものとなります。つまりこの区間 は「操作によって実質的に並び替えられたのはどの区間か」というものを表します。
求めたい答えは、 通りの全ての操作パターンについてこのようなインデックスの組 を求めた時の、それらの相異なる要素数となります。ただし1つも要素が変更されない場合もあるので、その場合は適当に などとしておきます。(開区間と紛らわしいので値の組は と表記します)
では各操作パターンについて、長さ の区間 を操作したときの はどのように求めれば良いでしょうか。左右同様の方法で求められるので について考えます。
左端から見て、要素が変更されていない区間 に注目します。この区間に属する全ての値 が満たすべき条件は、 より小さい要素が区間 に存在しないことです。
このような条件を満たす区間のうち最も長いものを求めることができれば、その区間を として の値を求めることができます。そしてこれは二分探索で求めることができます。
具体的には、あらかじめ各インデックス について「 より小さい要素が右側で次に現れるのはどこか」を求めておきます(存在しない場合は適当に大きな数とします)。この値を としましょう。
そうすると区間 の値が変更されない必要十分条件は、区間内の全ての について が区間 の外にあること、つまり
が成立することなので、 の値をSparse Tableやセグメント木などに入れておくことで効率的にこの判定が出来て、二分探索をすることができます。
また の値も、 そのものをSparse Tableに入れて二分探索したり、 を右から見ていきながらセグメント木に入れていくことで求めることができます。
についても、左/右や小さい/大きいを逆にして考えると同様に計算できます。これで各操作に対する の値が求められるので、 値の組 をset等に入れて相異なる要素数を数えることで答えを求めることが出来ます。