一.题目链接:

Second Large Rectangle

二.题目大意:

给你一个 n × m 大小的由{0,1} 组成的矩阵.

求全由 1 构成的子矩阵中面积的次大值,不存在则输出 0.

三.分析:

求存在障碍点的最大子矩阵,可以用悬线法或单调栈.

不过这里让求次大子矩阵(悬线法求的时候有重复,这个菜鸡不会,有大佬请留言)

所以这里只写了单调栈的解法.

思想就是,求出 h[i][j],h[i][j]的定义:点(i,j)能够向上拓展的长度.

例如矩阵 A:

A 的 h 矩阵为:

之后再枚举矩阵的底边,用单调栈就可以了.

存在障碍点的最大子矩阵学习:借鉴

很经典的国家集训队论文:浅谈用极大化思想解决最大子矩形问题

四.代码实现:

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;

const int M = (int)1e3;
const ll inf = 0x3f3f3f3f3f;

int st[M + 5];
int width[M  +5];
int h[M + 5][M + 5];

priority_queue <int, vector<int>, greater<int> > q;

/**
4 4
1111
1011
1101
1111
**/

void add(int x)
{
    q.push(x);
    while(q.size() > 2)
        q.pop();
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    int x;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            scanf("%1d", &x);
            h[i][j] = x ? h[i - 1][j] + 1: 0;
        }
        h[i][m + 1] = 0;
    }
    q.push(0);
    q.push(0);
    for(int i = 1; i <= n; ++i)
    {
        int top = 0;
        for(int j = 1; j <= m + 1; ++j)
        {
            if(st[top] < h[i][j])
            {
                st[++top] = h[i][j];
                width[top] = 1;
            }
            else
            {
                int w = 0;
                while(st[top] > h[i][j])
                {
                    w += width[top];
                    add(st[top] * w);
                    add(st[top] * (w - 1));
                    add((st[top] - 1) * w);
                    top--;
                }
                st[++top] = h[i][j];
                width[top] = w + 1;
            }
        }
    }
    printf("%d\n", q.top());
    return 0;
}