@(K ACMer)
题意:
给你一个n *m的01矩阵,求其中元素全为0的最大子矩阵的最大面积.
分析:
最暴力的方法是枚举每一个点为子矩阵左上顶点,然后来暴力判断以它为顶点的最大0子矩阵的最大大小.这样重的复杂度是
O(n4)
,TLEEEEEEEE
也可以DP一下,复杂度是
O(n3)
,还是TLEEEE..
无法可解…
看了别人的做法:
维护一个前缀,然后对每个前缀想形成矩阵都要找其左右两边第一个小于它的.那么这个时候就可以用单调栈来维护了.
这样总的复杂度是
O(n∗m)
,分非常优雅.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e3 + 40;
int a[maxn][maxn], n, m, b[maxn][maxn], ans;
pair<int, int> temp[maxn];
void getit(void) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (a[i][j] == 0) b[i][j] = b[i][j - 1] + 1;
}
}
void doit(void) {
for (int i = 1; i <= m; i++) {
stack<int> st;
for (int j = 1; j <= n; j++) {
if (st.empty() || b[j][i] > b[st.top()][i]) {
if (!st.empty()) temp[j].first = st.top();
else temp[j].first = 0;
st.push(j);
} else {
while (!st.empty() && b[st.top()][i] >= b[j][i]) {
temp[st.top()].second = j;
st.pop();
}
if (st.empty()) temp[j].first = 0;
else temp[j].first = st.top();
st.push(j);
}
}
while (!st.empty()) {
temp[st.top()].second = n + 1;
st.pop();
}
for (int j = 1; j <= n; j++)
ans = max(ans, (temp[j].second - temp[j].first - 1) * b[j][i]);
}
}
int main(void) {
int T;
scanf("%d", &T);
while (T--) {
ans = -INF;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
b[i][0] = 0;
for (int j = 1; j <= m; j++)
scanf("%d", &a[i][j]), b[i][j] = 0;
}
getit();
doit();
printf("%d\n", ans);
}
}