题目链接
dp+单调栈
用dp[i][j] 记录位置(i,j)竖直向上有多少个连续的1
从某一行从左到右扫一遍,就能呈现出条形图,记录条形图中所有可能的矩形面积。
用单调递增的单调栈维护条形图的高度,依次记录第二小的面积。
#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
const int Maxn = 1000+10;
const int INF = 0x3f3f3f3f;
int dp[Maxn][Maxn];
int max_1 = -INF, max_2;
void cal(int w, int h) {
if(max_1 < w*h) {
max_2 = max_1;
max_1 = w*h;
} else max_2 = max(max_2, w*h);
if(max_1 < (w-1)*h) {
max_2 = max_1;
max_1 = (w-1)*h;
} else max_2 = max(max_2, (w-1)*h);
if(max_1 < w*(h-1)) {
max_2 = max_1;
max_1 = w*(h-1);
} else max_2 = max(max_2, w*(h-1));
}
int main(void)
{
int n, m;
cin >> n >> m;
char s[Maxn];
for(int i = 0; i < n; ++i) {
cin >> s;
for(int j = 0; j < m; ++j) {
dp[i][j] = s[j]-'0';
if(i-1 >= 0 && dp[i][j] == 1) dp[i][j] += dp[i-1][j];
}
}
stack <int>sk;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(j+1 < m && dp[i][j+1] == dp[i][j]) continue;
int tmp = -1;
while(!sk.empty() && dp[i][j] < dp[i][sk.top()]) {
int indx = sk.top();
if(tmp == -1) tmp = indx;
sk.pop();
if(!sk.empty()) cal(tmp-sk.top(), dp[i][indx]);
else cal(tmp+1, dp[i][indx]);
}
sk.push(j);
}
int tmp = -1;
while(!sk.empty()) {
int indx = sk.top();
if(tmp == -1) tmp = indx;
sk.pop();
if(!sk.empty()) cal(tmp-sk.top(), dp[i][indx]);
else cal(tmp+1, dp[i][indx]);
}
}
cout << max_2 << endl;
return 0;
}