链接:https://ac.nowcoder.com/acm/contest/888/A
题意:给出一个只含'0'或'1'的n*m的矩阵。求有多少个全是'1'的极大子矩阵。
思路:预处理每一行中每一列连续1的高度(h[i][j]表示从第i行第j列开始向上有多少个连续的1。)和每一行每一列中1的前缀和(sum[i][j]表示第i行前j个数有多少个1)。枚举每一行,用单调栈维护每一列的作用范围,最后再枚举每一列j,如果下一行l[j]到r[j]中1的个数也是r[j]-l[j]+1,说明该子矩阵不是极大子矩阵;否则,代表是。但是,有可能把同一个子矩阵计算多次,所以要去重。可以用map标记,也可以再维护一个非严格递增的单调栈,如果此列的高度和栈顶代表列的高度相同就不计算,因为已经计算过该子矩阵了。
1.map标记
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e3+10;
char mp[N][N];
int n,m,sum[N][N],h[N][N],l[N],r[N],sta[N],top;
ll ans;
map<int,map<int,int> > vis;
int main(void)
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)
{
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++)
{
h[i][j]=(mp[i][j]=='1')?h[i-1][j]+1:0;
sum[i][j]=sum[i][j-1]+(mp[i][j]=='1');
}
}
for(int i=1;i<=n;i++)
{
top=0;
for(int j=1;j<=m;j++)
{
while(top&&h[i][sta[top]]>=h[i][j])
top--;
if(top) l[j]=sta[top]+1;
else l[j]=1;
sta[++top]=j;
}
top=0;
for(int j=m;j>=1;j--)
{
while(top&&h[i][sta[top]]>=h[i][j])
top--;
if(top) r[j]=sta[top]-1;
else r[j]=m;
sta[++top]=j;
}
vis.clear();
for(int j=1;j<=m;j++)
{
if(h[i][j]&&sum[i+1][r[j]]-sum[i+1][l[j]-1]!=r[j]-l[j]+1)
{
if(!vis[l[j]][r[j]])
{
ans++;
vis[l[j]][r[j]]=1;
}
}
}
}
printf("%lld\n",ans);
return 0;
}
2.单调栈维护
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e3+10;
char mp[N][N];
int n,m,sum[N][N],h[N][N],l[N],r[N],sta[N],top;
ll ans;
int main(void)
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)
{
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++)
{
h[i][j]=(mp[i][j]=='1')?h[i-1][j]+1:0;
sum[i][j]=sum[i][j-1]+(mp[i][j]=='1');
}
}
for(int i=1;i<=n;i++)
{
top=0;
for(int j=1;j<=m;j++)
{
while(top&&h[i][sta[top]]>=h[i][j])
top--;
if(top) l[j]=sta[top]+1;
else l[j]=1;
sta[++top]=j;
}
top=0;
for(int j=m;j>=1;j--)
{
while(top&&h[i][sta[top]]>=h[i][j])
top--;
if(top) r[j]=sta[top]-1;
else r[j]=m;
sta[++top]=j;
}
top=0;
for(int j=1;j<=m;j++)
{
if(!h[i][j])
{
while(top) top--;
continue;
}
while(top&&h[i][sta[top]]>h[i][j]) top--;
if(!top||h[i][j]!=h[i][sta[top]])
{
if(sum[i+1][r[j]]-sum[i+1][l[j]-1]!=r[j]-l[j]+1)
ans++;
}
sta[++top]=j;
}
}
printf("%lld\n",ans);
return 0;
}