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

题目传送门

题意:

输入n和m,给出一个n行m列的01矩阵,求出所有的不可扩大的全1矩阵个数。

题解:

预处理每个格子的高度up[i][j](其向上连续的1的个数),枚举每一行 i,维护单调栈(单调上升)求每个格子 j 以up[i][j]为高可达到的全1矩阵左边界pos和右边界j,此时得到的全1矩阵不能再向上左右拓展,只要判断能否再向下拓展即可。只要下一行[pos,j]区间内有0存在,即该全1矩阵不能向下拓展。

维护单调栈时,当前点高度等于栈顶元素高度,则说明是重复的,不用计算。

Code:

手写栈:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=3005;
 4 int a[maxn][maxn],sum[maxn][maxn],up[maxn][maxn],height[maxn],sta[maxn];
 5 int main()
 6 {
 7     int n,m;
 8     scanf("%d%d",&n,&m);
 9     for(int i=1;i<=n;i++){
10         for(int j=1;j<=m;j++){
11             scanf("%1d",&a[i][j]);
12             up[i][j]=(a[i][j]==1)?up[i-1][j]+1:0;//预处理每个格子(i,j)向上的连续的1的个数
13             sum[i][j]=sum[i][j-1]+a[i][j];//预处理每行的前缀和,方便判断矩形能否向下拓展
14         }
15     }
16     int ans=0;
17     for(int i=1;i<=n;i++){
18         int top=0;
19         for(int j=1;j<=m+1;j++){
20             int pos=j;
21             while(top&&up[i][j]<height[top]){ 
22                 if(i==n||(sum[i+1][j-1]-sum[i+1][sta[top]-1])<j-sta[top])//不可向下拓展,答案+1
23                     ans++;
24                 pos=sta[top];//向左最远能拓展的位置pos
25                 top--; //出栈
26             }
27             if(up[i][j]&&(!top||up[i][j]>height[top])) //入栈
28                 height[++top]=up[i][j],sta[top]=pos;
29         }
30     }
31     printf("%d\n",ans);
32     return 0;
33 }

STL的stack:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=3005;
 5 int a[maxn][maxn],up[maxn][maxn];
 6 int main()
 7 {
 8     int n,m;
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++){
11         for(int j=1;j<=m;j++){
12             scanf("%1d",&a[i][j]);
13             up[i][j]=(a[i][j]==1)?up[i-1][j]+1:0;
14         }
15     }
16     int ans=0;
17     for(int i=1;i<=n;i++){
18         int temp=0;
19         stack<pair<int,int> >S;
20         for(int j=1;j<=m+1;j++){
21             int pos=j;
22             while(!S.empty()&&up[i][j]<S.top().first){
23                 if(S.top().second<=temp)//下一行[pos,j]中有0存在,故不可向下扩展,答案+1
24                     ans++;
25                 pos=S.top().second;
26                 S.pop();
27             }
28             if(!up[i+1][j])temp=j;//记录下一行中截至当前最右边0的位置
29             if(S.empty()||up[i][j]>S.top().first)
30                 S.push({up[i][j],pos});
31         }
32     }
33     printf("%d\n",ans);
34     return 0;
35 }

猜你喜欢

转载自www.cnblogs.com/HOLLAY/p/11350856.html