数列を昇順に並べ替えたものをとする。最大値-最小値をすべて試すなら、だいたい次のようになるはずだ。
- 数列の小さいほうから個取り除いて最大値-最小値を求める。
- を残したままにしつつからできるだけ小さい数を取り除いてゆき、個取り除けたら最大値-最小値を求める。
- を残したままにしつつからできるだけ小さい数を取り除いてゆき、個取り除けたら最大値-最小値を求める。
- …
これは高々ステップで済むので、ひとつひとつのステップがかくらいで実行できればよい。
小さい数を取り除いていく具体的な手順を与えるために、上のステップ3について考えてみる。とする。
, を残したまま数を取り除いていくというのは、上の数列の縦線をまたがないように連続した個を選んで、その最小値を除いていくということにほかならない。なぜならはほかの数より小さいので、縦線をまたぐとが取り除かれてしまうからだ。つまり、を複数の独立した数列に分割してそれぞれの最小値を見ればよさそうだ。
さて、「複数の独立した数列」をどう管理すればよいかが問題である。上の3つの部分列をとする。これらの数列から小さい数を除いていくとき、数列の最小値と長さにしか興味がないので、はそれぞれ(昇順の)優先度付きキューで表すことができる。さらに、自身も優先度付きキューにいれることにし、の順序は の最小値の最小値 とする。
一般に、個の部分列から個の数を取り除く操作を書き下すと、次のようになる。
- の中で長さが以上であるものだけに入れて、残りは捨てる。
- 次のステップを最大回繰り返す。
- の先頭から数列を取り出す。
- の最小値を取り出す。
- の長さがまだ以上ならに戻し、未満なら捨てる。
- が空になる前に個の数を取り出せたなら、その最大値-最小値を求める。
以上で答えが求まる。全体の計算量は。
問題を読んだときはが小さいので何をやってもできそうな気がしたけど、具体的な手順を与えるのに膨大な時間をかけてしまった。