牛客暑假多校第二场H Second Large Rectangle

题目描述:

在这里插入图片描述

题意:

给一个n*m的01矩阵,一个矩阵中如果全是1则它是合理的,求这个矩阵第二大的合理子矩阵。

题解:

按层来考虑,考虑以第i层为底面的时候,对于第j列来说,从 ( i , j ) , ( i − 1 , j ) . . (i,j),(i-1,j).. (i,j),(i1,j)..往上的连续h个1组成一个高为h,底面为1的柱子。
在这里插入图片描述
那么对于每一个柱子,用单调栈求出以该柱子为高的矩形的最大面积。
但是这样可能会重复计算同一个矩阵的面积,比如两个柱子高度都是3,那这个面积为6的矩阵会被计算两次,这样次大和最大都是6了,但是实际上只有一个面积为6的矩形:
在这里插入图片描述
我们可以只用最左边的柱子去算,具体操作就是:对于一个柱子 h j h_j hj,它左边第一个小于它的柱子的位置是 l l l,如果 ( l , j ) (l,j) (l,j)这段区间有一个柱子的高度等于 h j h_j hj,那么 h j h_j hj这个柱子就直接跳过。
还有一个问题就是,需要求的是次大的矩形,这个矩形也可能包含在最大的矩阵之中,所以还要求一下当前最大矩形削掉一行的面积,削掉一列的面积,判断是不是比当前的次大面积要大。

ac代码:

#include<bits/stdc++.h>
using namespace std;
int n, m;
int fi, se;
const int maxn = 1e3 + 50;
int h[maxn];
int flag[maxn];
char str[maxn];
stack<int> s;
int l[maxn], r[maxn];
int main()
{
    scanf("%d%d", &n, &m);
    h[0] = h[m + 1] = -1;
    fi = se = -1;
    for(int i = 1; i <= n; ++i){
        scanf("%s", str + 1);
        for(int j = 1; j <= m; ++j){
            if(str[j] == '0') h[j] = 0;
            else h[j]++;
        }
        while(s.size()) s.pop();
        s.push(0);
        for(int j = 1; j <= m; ++j){
            flag[j] = 0;
            while(s.size() && h[s.top()] >= h[j]) {
                if(h[s.top()] == h[j]) {
                    flag[j] = 1;
                }
                s.pop();
            }
            l[j] = s.top();
            s.push(j);
        }

        while(s.size()) s.pop();
        s.push(m+1);
        for(int j = m; j > 0; --j){
            while(s.size() && h[s.top()] >= h[j]) s.pop();
            r[j] = s.top();
            s.push(j);
        }
        for(int j = 1; j <= m; ++j){
            if(flag[j]) continue;
            int t = h[j]*(r[j] - l[j] - 1);
            if(t >= fi){
                se = fi;
                fi = t;
            }
            else if(t > se) se = t;

            t = max(h[j]*(r[j] - l[j] - 2), (h[j] - 1)*(r[j] - l[j] - 1) ) ;
            if(t > se) se = t;
        }

    }
    if(se == -1) cout<<0<<endl;
    else cout<<se<<endl;
}

正解的DP待补……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值