Codeforces 514Dの解いろいろ

http://d.hatena.ne.jp/phyllo_algo/20150215/1423985061

Codeforces 514のD問題をかなり微妙な解法で通ってしまっていたけど、テストケースが35個ぐらいでそんなに悪意のあるケースがないためたまたま通ってしまっているようにも思われる。


http://kmjp.hatenablog.jp/entry/2015/02/15/0930
http://codeforces.ru/blog/entry/16398

解法はいろいろあるようだけど、想定解法がO(NM)のようで、しゃくとり法+s〜eの最大値をO(1)で求めることになっている。uwiさんに「スライド最大値」という方法を教えてもらったのでまとめておく。

O(N^2 M)+無駄な計算を省く

http://d.hatena.ne.jp/phyllo_algo/20150215/1423985061
上のところで書いた方法で、しゃくとり法のときにs〜eの最大値をもとめてs+1していくのではなく、eから条件を満たす間sを広げていく方法。
しかし、これはO(N^2 M)なので、うんこ。撃墜。
(s〜eが大きくて、s〜e+1が条件を満たさずs+1〜e+1が条件を満たすようなものが連続するようなもの、、、作れるか怪しい)。

撃墜ケースの例

machyさんに、以下のケースでhackされました。(手元MBAでは25秒ぐらい)

100000 5 100000
99996 1 1 1 1
99995 1 1 1 1
...
74997 1 1 1 1
1 1 1 1 1
...
1 1 1 1 1
1 2 1 1 1
...
1 25001 1 1

「1 1 1 1 1」までは条件を満たすのでeを伸ばせるが、「1 2 1 1 1」は「99995 1 1 1 1」まで戻らないといけないので、大雑把に25000*75000*5=9.4*10^9回参照が必要になる。なるほど。


O(Nlog(N)M)解

しゃくとり法であれば、s〜eの最大値を効率的に求めるのに、SegTreeを使うとO(log(N))で求められる。
sを固定して、最大のeをSegTreeの二分探索で求める方法でもO(log(N))になる。

O(Nsqrt(N)M)解

kmjpさんのブログで紹介されている、平方分割でeを求めるとO(sqrt(N))になる。

O(NM)解

しゃくとり法で、s〜eの最大値をO(1)で求める必要がある。
これは「スライド最大値/最小値」という両端queue(deque)を使う方法を使うと実現できる(蟻本上級編)。
蟻本では、dequeを、「i