如果我的博客费解,可以看这篇博客,认为清晰。
首先把子矩阵预处理,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 ", ans); return 0; }