题目链接

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;
}