Codeforces Round #574 - E. OpenStreetMap
概要
n行m列の行列がある。それからa行b列の部分行列を切り出す。(n-a+1) * (m-b+1)個できる。部分行列の項の最小値の和を(n-a+1)*(m-b+1)個分足した値を答えよ。
ただし、n行m列の行列はとして、である。
制約: 1 <= a <= n <= 3000, 1 <= b <= m <= 3000, 0 <= x, y, z <= 10^9
ACするまで
1. 与式で構築された行列、数学的な規則を利用して解くのはなさそう。
2. 典型を感じる。2次元セグメント木でいけそう(後述)
3. 1次元ならば、サイズ固定なのでスライド最小値で行けそう。でも2次元。。。
4. よく考えてみたらスライド最小値は軸ごとに独立。2回やればいいので終わり->AC!
考察
このスライド最小値というテクニック、蟻本にもある。(上級編)公式解説の貼ってあるページはスライド最小値の紹介。
このスライド○○シリーズはおそらくモノイドならばすべてできると思う。(調べます)
ACソースコード:
2Dセグメント木
2次元セグメント木といって、サイズ可変の区間取得がO(logH log W)、1点更新もO(logH logW)のデータ構造がある。これでも今回の問題は理論上解くことができるが、僕が投げてみたところ、TLEではなくMLEしてしまった。3000 * 3000の配列の実質4倍確保するアルゴリズムなので、メモリ関連が意外に厳しかった。
MLEソースコード:
一言
There is almost nothing to say about this problem. It is pretty standard data structure problem.
これを解けないのは俺が悪い。