牛客多校8a题补题 利用单调栈来求解(太菜了,继续加油把)

链接:https://ac.nowcoder.com/acm/contest/888/A
来源:牛客网

Gromah and LZR entered the great tomb, the first thing they see is a matrix of size n\times mn×m, and the elements in the matrix are all 0_{}0

or 1_{}1

.

LZR finds a note board saying “An all-one matrix is defined as the matrix whose elements are all 1_{}1

, you should determine the number of all-one submatrices of the given matrix that are not completely included by any other all-one submatrices”.

Meanwhile, Gromah also finds a password lock, obviously the password should be the number mentioned in the note board!

Please help them determine the password and enter the next level.
:求解最大的不被覆盖的子矩阵的个数

这种题目一般需要想到的第一种想法就是枚举!!! 枚举每一行 那么到底枚举什么呢,就枚举以i , j 这个为底的矩形的大小 判断这个矩形能不能被算入答案 , 一个矩形能不能被算作答案的话 那么他需要不能被下面的继承 也就是以我当前矩形为高的这个矩形 我当前最远的左端为pos 右端为j 如果在这段中我下面不是全部都是1 那么我肯定没有被别的覆盖 可以算作答案 但是如果我被再右边的覆盖了怎么办呢 这个时候就需要判断一下,可以利用单调栈来维护这个东西 如果后面的比我当前的高还大 那么就把后面的矩阵给直接入站 当我后面的比我低的话 这个时候就需要考虑是否能够出栈 然后ans++了 如果我pos到j这段下面有0,那么我答案肯定是可以++的 如果没有那么这个肯定是被覆盖了 直接不管 对于加入进来把前面的弹出去的 一定要更新当前的pos等于之前被弹出去的pos,因为的就相当于从大块的继承了一部分过来

最后一个j要等于m + 1 当我前m个都没有完的时候 要进行一次最后的出栈 判断一下当前栈里面有多少个符合情况的 当前的栈里面肯定都是递增的 只需要一个一个判断下面是否有0,记录答案就好了

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>

typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 3e3 + 10;
const long long int inf = 1e17 + 10;

int h[maxn][maxn];

char mp[maxn][maxn];



int main()
{

    int n,m;
    scanf("%d%d",&n,&m);
    getchar();
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%c",&mp[i][j]);
        }
        getchar();
    }
    for(int i = 1; i <= m + 1; i++) mp[n + 1][i] = '0';
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            h[i][j] = ( mp[i][j] == '0' ? 0 : h[i - 1][j] + 1 );
        }
    }
    stack<pii> sta;
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        while(!sta.empty()) sta.pop();

        int temp = -1;
        int pos;

        for(int j = 1; j <= m + 1; j++) // is not enough just add one
        {
            pos = j;
            while(!sta.empty() && sta.top().fi > h[i][j])
            {
                if(sta.top().se <= temp) ans++;
                pos = sta.top().se;
                sta.pop();
            }
            if(mp[i + 1][j] == '0') temp = j; // 最近的0在哪里
            if(h[i][j] && (sta.empty() || h[i][j] > sta.top().fi))
            {

                sta.push(pii(h[i][j],pos));
            }
        }
        //cout<<ans<<endl;
    }
    cout<<ans<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值