题目链接
大意:给你一个01矩阵,求全1的极大子矩阵的个数
思路:我们考虑用单调栈解决,先预处理出每个1向上能延伸的最大高度 u[i][j],然后我们枚举下边界,然后每个边界遍历每列,维护一个高度递增的单调栈,每个元素记录向左能延申到的最小位置 pos,每次弹出的元素若满足向下无法延申的情况即可计入答案。
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 2e5 +11;
int n,m;
char a[3333][3333];
int u[3333][3333],sum[3333][3333];
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i]+1;
for(int j=1;j<=m+1;j++){
int x=j<=m?(a[i][j]=='1'):0;
if(a[i][j]=='1'){
u[i][j]=u[i-1][j]+1;
}
sum[i][j]=sum[i][j-1]+x;
}
}
int ans=0;
for(int i=1;i<=n;i++){
stack<pair<int,int> >q;
int pos=-1,now=0;
for(int j=1;j<=m+1;j++){
int pos=j;
while(!q.empty()&&u[i][j]<q.top().fi){
auto x=q.top();
q.pop();
if(sum[i+1][j-1]-sum[i+1][x.se-1]!=j-x.se)ans++;
pos=x.se;
}
if(u[i][j]&&(q.empty()||q.top().fi<u[i][j]))q.push({u[i][j],pos});
}
}
cout<<ans<<endl;
return 0;
}