51nod 1158 全是1的最大子矩阵

题目链接在这儿

如果我的博客费解,可以看这篇博客,认为清晰。

首先把子矩阵预处理,g[i][j]表示第[i][j]号元素能向左延伸的长度。

进而针对每一列,假设是c列,考虑g[i][c],i∈[1, Row],得到g[i][c]元素在这一列上作为作为最小值的长度。

假设这个区间是(U, D),那么长度为D-U-1,那么临时解为(D-U-1)*g[i][j]。取临时解中的最大值即为答案。

这里要利用单调栈,或者用我用的比较简洁的写法都ok,理解了解法自己写比较好,复杂度O(N^2)。

 

为何是这样:举个例子,假设有下面描述的第5列左连续的值为2 4 3 5 2:

00011

01111

00111

11111

00011

考虑第三行第五列的值3,在这列上它作为最小值的开区间是(1, 5),闭区间是[2, 4],一个解即为(5-1-1)*3=9。

对代码的解释:U[i]和D[i]分别表示列上某一元素i,作为最小值能覆盖的左开区间点UP和右开区间点DOWN。

#include <stdio.h>
#include <iostream>
using namespace std;

const int maxN=5e2+5;
int N, M, K, T;
int g[maxN][maxN], U[maxN], D[maxN];

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= M; ++j) {
            scanf("%d", &g[i][j]);
            if (g[i][j])
                g[i][j] = g[i][j - 1] + 1;
        }
    }
    int ans = 0;
    for (int c = 1; c <= M; ++c) {
        for (int i = 1; i <= N; ++i) {
            U[i] = i - 1;
            D[i] = i + 1;
        }
        for (int r = 1; r <= N; ++r)
            while (U[r] && g[U[r]][c] >= g[r][c])
                U[r] = U[U[r]];
        for (int r = N; r >= 1; --r)
            while (D[r] <= N && g[D[r]][c] >= g[r][c])
                D[r] = D[D[r]];
        for (int r = 1; r <= N; ++r)
            ans = max(ans, (D[r] - U[r] - 1) * g[r][c]);
    }
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2018-08-23 11:49  gaawing  阅读(269)  评论(0编辑  收藏  举报