AOJ0310 枠
この高速化テクは典型らしいです。
問題
のグリッドがあり、各マスに数が書かれている。
このグリッドに太さ1マス分の長方形の枠をのせ、枠が覆っているマスの数の総和を最大化する。
ただし、枠は や
や
のように、中央に穴が空いていない場合もある。(詳しくは問題文の図を見て)
制約
想定TLE
累積和をしてから、枠の左上と右下を全探索( )して、それぞれの枠についての総和をO(1)で求め、最大値を答える。
2次元累積和+長方形領域の総和を求めるパートくらいバグらせずに素早く書けるようにしましょう。
ちなみにこの問題を見た当初は 300^4くらいいける!w と思って書いてTLEしました(バカかな?)
解法
累積和して区間の総和を で求めるのは変わりません。
しかし、枠の4辺を全探索すると で間に合いません。
に落としたいので、とりあえず2辺を
で全探索して、残り2辺を
で決めることにします。
ここで、2辺を でしようとしたときに、しゃくとりを思い浮かべると、対辺をペアにするという発想ができます。
上下と左右、どっちを全探索しても本質的には同じなので、ここでは上下を全探索することにします。
行目を上の辺、
行目を下の辺として、総和が最大になるように右辺(
)と左辺(
)を決めます。

まず 行目と
行目を採用することは決まっているので、
行目と
行目のマスの総和を計算しておきます。ここでは、枠を決めたときのその総和からの差分を最大化していきます。
右辺と左辺を一度に考えるのは難しいので、先に右辺から考えます。
右辺を 列目にすると決めたとき、
行目の
列目以降の部分
行目の
列目以降の部分
は、枠には関係ない部分なので、不要になります。
逆に、
列目の
行目から
行目の部分
は枠の一部なので必要になります。

よって
( 列目の
行目から
行目の部分) - (
行目の
列目以降の部分) - (
行目の
列目以降の部分)
を計算してあげればよいです。
これを のすべての
について求めてあげます。
そして、左辺の についても同様で、
行目の
列目より前の部分
行目の
列目より前の部分
は、枠には関係ない部分なので、不要になります。
逆に、
列目の
行目から
行目の部分
は枠の一部なので必要になります。

よって
( 列目の
行目から
行目の部分) - (
行目の
列目より前の部分) - (
行目の
列目より前の部分)
を計算してあげればよいです。
これを のすべての
について求めてあげます。
これで前計算が終わったので、あとはこれらをうまく組み合わせて右辺と左辺を最適に選びます。
たとえば、 を決めると、最大となる
は、
をみたすもののうち、さっき計算した差分が最大となる
です。これは「右端が
列目以降であるときの最大値」などを前計算してあげると
で求められるので、右辺と左辺を計算するのは全体で
でできます。(実際は
の場合などは別で計算した方が簡単になります)