2019牛客多校第八场——A. All-one Matrices【单调栈】
题目链接:https://ac.nowcoder.com/acm/contest/888/A
建议先看这个:https://ac.nowcoder.com/acm/contest/882/H
第二场单调栈求第二大矩形面积比较容易理解!!!
对应博客:https://blog.youkuaiyun.com/qq_43653111/article/details/99174679
题意:给你一个01矩阵,求不可扩大的全1矩形的个数。
思路:牛客第二场的时候出了一个求最大(第二大)1矩形面积,当时看成直方图面积求每一列的单调栈相乘就行了。这题也是类似,只不过多了一个向上能延伸到多少。
对于每一个[i,j],记录从它开始向上连续的1的个数num;
枚举每一行作为矩阵底边所在行,从后向前枚举每一列,维护一个num单调上升的栈,对于栈中每一个num值,还要维护一个该num对应位置向左最远能扩展到的位置pos;
元素出栈时,设该元素是(num,pos),那么可以得到一个全1矩阵(i-num+1,pos)->(i,j);
此时该矩阵最左为pos已经记录(不可向左扩展),向上最多为num已经记录(不可向上扩展),因为大于当前num才出栈(不可向右扩展),所以只要判定能否向上扩展,如果不能,那么这就是一个答案矩阵。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
int l[maxn],r[maxn],mx[maxn][maxn],a[maxn][maxn];
char c;
stack<int>s;
int n,m,x,ans=0;
int main()
{
memset(mx,0x3f,sizeof(mx));///相当于vis数组,标记向上能延伸哪里
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%1d",&x);
if(x==1)
a[i][j]=a[i-1][j]+1;///类似于直方图
else
a[i][j]=0;
}
}
for(int i=n; i>=1; i--)
{
while(!s.empty())
s.pop();
for(int j=1; j<=m; j++)///单调栈l[]数组
{
if(j==1)
s.push(j),l[j]=1;
else
{
while(a[i][s.top()]>=a[i][j])
{
s.pop();
if(s.empty())
break;
}
if(s.empty())
l[j]=1;
else
l[j]=s.top()+1;
s.push(j);
}
}
while(!s.empty())
s.pop();
for(int j=m; j>=1; j--)///单调栈r[]数组
{
if(j==m)
s.push(j),r[j]=m;
else
{
while(a[i][s.top()]>=a[i][j])
{
s.pop();
if(s.empty())
break;
}
if(s.empty())
r[j]=m;
else
r[j]=s.top()-1;
s.push(j);
}
}
for(int j=1; j<=m; j++)///从后往前遍历和更新,以免重复
{
if(a[i][j]&&i<mx[l[j]][r[j]])
{
ans++;
mx[l[j]][r[j]]=i-a[i][j]+1;
}
}
}
cout<<ans<<endl;
}