2019牛客暑期多校训练营(第八场)-A All-one Matrices (单调栈+前缀和)

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

题意:给n×m的01矩阵,求出其中全为1的矩阵个数(不被其它全1矩阵包括)。

思路:和第二场多校的次大子矩阵类似。二维降一维,遍历行,以第i行为矩阵的底,通过单调栈得到矩阵向左向右能够扩展的范围 l[j]和r[j],然后关键在去重。有两种重复,第一种是同一行中的矩阵,可以用二维矩阵vis[l[j]][r[j]]标记此范围的矩阵已被记录。对于列的重复,是因为此时的矩阵能在下一行得到行扩展,所以预处理得到下一行的‘1’个数的前缀和num[j],通过判断num[r[j]-1]-num[l[j]]==r[j]-l[j]-1来判断是否能扩展到下一行,能的话当前不记录。

AC代码:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=3005;
int n,m,ans;
int a[maxn][maxn],stk1[maxn],stk2[maxn];
int l[maxn],r[maxn],num[maxn],vis[maxn][maxn];
char c[maxn][maxn];

int main(){
    scanf("%d%d",&n,&m);
    for(register int i=1;i<=n;++i){
        a[i][0]=a[i][m+1]=-1;
        scanf("%s",c[i]+1);
        for(register int j=1;j<=m;++j){
            register int tmp=c[i][j]-'0';
            if(tmp) a[i][j]=a[i-1][j]+1;
        }
    }
    stk1[0]=0,stk2[0]=m+1;
    for(register int i=1;i<=n;++i){
        register int p1=1,p2=1;
        for(register int j=1;j<=m;++j){
            while(a[i][stk1[p1-1]]>=a[i][j]) --p1;
            l[j]=stk1[p1-1];
            stk1[p1++]=j;
        }
        for(register int j=m;j>=1;--j){
            while(a[i][stk2[p2-1]]>=a[i][j]) --p2;
            r[j]=stk2[p2-1];
            stk2[p2++]=j;
        }
        for(int j=1;j<=m;++j)
            num[j]=num[j-1]+(c[i+1][j]=='1');
        for(register int j=1;j<=m;++j){
            if(!a[i][j]) continue;
            if(vis[l[j]+1][r[j]-1]==i) continue;
            if(num[r[j]-1]-num[l[j]]==r[j]-l[j]-1) continue;
            ++ans;
            vis[l[j]+1][r[j]-1]=i;
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/FrankChen831X/p/11333189.html