牛客网多校训练第八场A All one Matrix


题目链接:https://ac.nowcoder.com/acm/contest/888/A

题意:求出有多少个不被包含的全1子矩阵

解题思路:首先对列做处理,维护每个位置向上1的个数,然后我们从最后一行开始处理(方便去重),通过单调栈维护每个点左右第一个小于它的值的下标l[j],r[j],那么(l[j]-1,r[j]-1)就是以当前行为矩阵底的左右边界(左右无法再扩展,向上也不能),我们只需维护当前左右边界相同的矩阵,上一次所覆盖到的矩阵上边界,如果这个矩阵底所在行小于前一个相同左右边界矩阵的上边界所在行,那么这两个矩阵就是不存在包含关系的,ans++

#include 
using namespace std;
const int N = 3005;
int a[N][N],l[N],r[N],last[N][N];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    memset(last,0x3f, sizeof(last));
    getchar();
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)a[i][j] = getchar() == '0' ? 0 : a[i - 1][j] + 1;
        getchar();
    }
    int sta[N],top=0;
    int ans=0;
    for (int i = n; i >= 1; i--)
    {
        top=0,sta[0]=0;
        for(int j=1;j<=m;j++)
        {
            while (top&&a[i][sta[top]]>=a[i][j])top--;
            l[j]=sta[top];
            sta[++top]=j;
        }
        top=0,sta[0]=m+1;
        for(int j=m;j>=1;j--)
        {
            while (top&&a[i][sta[top]]>=a[i][j])top--;
            r[j]=sta[top];
            sta[++top]=j;
        }
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]&&i1][r[j]-1])//i要小于上次统计过的同左右边界矩阵的上边界
            {
                ans++;
                last[l[j]+1][r[j]-1]=i-a[i][j]+1;//记录当前统计矩阵的上边界
            }
        }
    }
    cout<endl;
    return 0;
}