G - One More Grid Task Editorial by MMNMM


ヒストグラムの最大長方形を求めるアルゴリズムを少し改変することでも、この問題を \(O(NM^2)\) 時間で解くことができます。

\(l _ y,r _ y\) を全探索し、数列 \(B _ i,C _ i\) を作るまでは https://atcoder.jp/contests/abc311/editorial/6833 と同じです。

すると、これは横幅が \(B _ i\) で高さが \(C _ i\) の長方形が連なったヒストグラムの最大長方形を求めることに帰着されます(ヒストグラムを連長圧縮したものと考えてもよいでしょう)。

ヒストグラムの最大長方形は stack を用いて線型時間で求められるため、この問題を \(O(NM^2)\) 時間で解くことができました。

実装の際には、末尾に幅も高さも \(0\) であるような長方形を番兵として置いておくと楽かもしれません。

#include <bits/extc++.h>
#include <atcoder/modint>

int main() {
    using namespace std;
    using modint = atcoder::static_modint<998244353>;
    unsigned N, M;
    cin >> N >> M;

    // ヒストグラムの最大長方形を求める
    // seq[i] = i 番目の (横幅, 高さ)
    const auto hisgram_maximum_rectangle{[](const auto &seq) {
        vector<pair<unsigned long, unsigned long>> hist;
        unsigned long result{};
        unsigned long now{};
        for (const auto[w, h] : seq) {
            unsigned long left{now};
            while (!empty(hist) && hist.back().second >= h) {
                result = max(result, (now - hist.back().first) * hist.back().second);
                left = hist.back().first;
                hist.pop_back();
            }
            now += w;
            hist.emplace_back(left, h);
        }
        return result;
    }};

    vector A(N, vector<unsigned long>(M));
    for (auto &&a : A)
        for (auto &&x : a)
            cin >> x;

    unsigned long ans{};
    for (unsigned long l{}; l < N; ++l) {
        vector<pair<unsigned long, unsigned long>> BC(M, {0, numeric_limits<unsigned long>::max()});
        BC.emplace_back(); // 番兵を置いておく
        for (unsigned long r{l}; r < N; ++r) {
            for (unsigned long i{}; i < M; ++i) {
                const auto[b, c]{BC[i]};
                BC[i] = {b + A[r][i], min(c, A[r][i])};
            }
            ans = max(ans, hisgram_maximum_rectangle(BC));
        }
    }
    cout << ans << endl;
    return 0;
}

posted:
last update: