Codeforces Round #641 (Div. 1) B. Orac and Medians
お題箱より。
問題概要
長さ の整数列 が与えられる。この数列に以下の操作を0回以上行ってよい。
- ある連続部分列 を選び、それら全てをその中央値で置き換える。ただしこの問題において、 個の値の中央値は小さい方から 番目の値とする。
ある整数 が与えられる。操作によって数列の全ての要素を にできるかどうか判定せよ。
制約
解法
長さ のケースは最初に処理します。唯一の要素が かどうかを見れば良いです。
なるべくシンプルな手順で目標を達成できないか考えましょう。目標達成から逆向きに考えていきます。
- 全ての要素を にするためには、連続して2個 が並んでいる部分をどこか1箇所作れば良いです。その2個と別の1個の3個に対して中央値を取ると必ず になり、これを繰り返すと全ての値を にできるからです。
- 連続した2個の を作るためには、長さ2以上の区間で中央値がちょうど になるものを探して操作するか、もしくは の隣に 以上の値が置かれている部分を作れば良いです。その2つの中央値を取ると必ず になるからです。
- の隣に 以上の値を置くためには、まず長さ2以上の区間で中央値が 以上になるものを探して操作し、その値を1.の手順と同様に の隣まで運べば良いです。
ここまで考えると、目標を達成するためには について
- である が存在する。
- 中央値が 以上になるような長さ2以上の区間が存在する。
をともに満たすことが十分条件であることが分かります。
そしてこれは必要十分条件になっています。中央値は元の値のうちのどれかになるので1.は必ず満たされている必要があり、もし2.のような区間が存在しなければ何度操作しても 以上の要素を増やすことができないからです。
あとはこれをチェックします。2.の条件については各要素を 以上であれば 、 未満であれば に置き換えた数列を考えます。「中央値が 以上になる」は「 以上の値が過半数存在する」と言い換えられるので、この に置き換えた数列において区間和が正である長さ2以上の区間を求めれば良く、これは累積和などを用いて解くことができます。
しかしもう少し単純な解法が存在し、実は2.の条件を確認するために調べるべき区間は長さ2または3の区間だけで十分であることが示せるので、全探索することもできます。
その理由は以下の通りです。先ほどの の表記を用います。もし長さ3の区間で過半数(つまり2個)の を持つものが存在しない場合、 同士の間には が少なくとも2個以上挟まっているはずです。つまり の密度が一番高いケースでも
という並びにしかならず、これでは区間和が正となる長さ2以上の区間は絶対に取れません。よって「もし長さ3で区間和が正であるものが存在しないならば、長さ4以上でも存在しない」ということが成り立つので、長さ2または3だけを調べれば十分です。