题目链接
大意:给你一个01矩阵,求全1的极大子矩阵的个数
思路:我们考虑用单调栈解决,先预处理出每个1向上能延伸的最大高度 u [ i ] [ j ] u[i][j] u[i][j],然后我们枚举下边界,然后每个边界遍历每列,维护一个高度递增的单调栈,每个元素记录向左能延申到的最小位置 p o s pos 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;
}