题目链接:https://ac.nowcoder.com/acm/contest/882/H
题解:找到第二大的,全是1的矩阵
题解:首先找最大的时候,就是单调栈,按照以当前高度作为最低来求的,但是这里求的是第二大,所以对于这个矩阵来说,要么高减一,要么宽减一,但要注意的是每个矩阵只能计算一次,比如高度为1 3 1,这样在计算两个一的时候会计算两次,想一下,对于这种情况,区间[l, r]是一样的,所以在计算的时候,把区间标记一下就可以了。
#include<cstdio>
#include<stack>
#include<iostream>
using namespace std;
const int maxn=1100;
int a[maxn][maxn];
int up[maxn][maxn],down[maxn][maxn];
char str[maxn];
int vis[maxn][maxn];
int n,m;
int max1, max2;
void update(int x) {
// cout << x << endl;
if(x > max1) {
max2 = max1;
max1 = x;
return;
}
if(x > max2) {
max2 = x;
}
return;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int x;
stack<int> s;
for(int i=1;i<=n;i++)
{
scanf("%s", str + 1);
for(int j=1;j<=m;j++)
{
if(str[j] == '1') a[i][j]=a[i][j-1]+1;
else a[i][j]=0;
}
}
for(int i=1;i<=m;i++)
{
while(!s.empty()) s.pop();
for(int j=1;j<=n;j++)
{
while(!s.empty()&&a[s.top()][i]>=a[j][i]) s.pop();
if(s.empty()) up[j][i]=1;
else up[j][i]=s.top()+1;
s.push(j);
}
}
for(int i=1;i<=m;i++)
{
while(!s.empty()) s.pop();
for(int j=n;j>=1;j--)
{
while(!s.empty()&&a[s.top()][i]>=a[j][i]) s.pop();
if(s.empty()) down[j][i]=n;
else down[j][i]=s.top()-1;
s.push(j);
}
}
max1 = 0, max2 = 0;
int ans;
for(int j=1;j<=m;j++) {
for(int i=1;i<=n;i++) {
if(a[i][j] != a[i - 1][j] && vis[up[i][j]][down[i][j]] == 0) {
ans=a[i][j]*(down[i][j]-up[i][j]+1);
update(ans);
vis[up[i][j]][down[i][j]] = 1;
}
if((down[i][j]-up[i][j]+1 - 1) >= 0) {
ans=a[i][j]*(down[i][j]-up[i][j]);
update(ans);
}
if(a[i][j] - 1>= 0) {
ans = (a[i][j] - 1) * (down[i][j]-up[i][j]+1);
update(ans);
}
}
for(int i = 1; i <= n; i++) {
vis[up[i][j]][down[i][j]] = 0;
}
}
printf("%d\n",max2);
}
return 0;
}
/*
5 2
10
01
11
01
10
*/