题解:
先预处理出以(i,j)为底的且都在j这一列的矩形的大小。即a[i][j]表示以(i,j)为底的矩形,宽为1,最长有多高。
然后对每一行进行扫描。
维护一个单调递增的单调栈。如果这一列的高度比栈顶低,就直接压入,否则就弹出栈(但要注意栈空的判断)。这样从左到右就可以得到向左,最多有多少行满足可以达到这一列的高度。同理,从右往左进行处理。
对于每一个位置都得到了一个满足这一个位置高度的最长的左右区间,找出最大的矩形面积即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N = 1000 + 10;
int n,m;
int mp[N][N],a[N][N];
int l[N],r[N];
struct node{
int height,pos;
};
stack<node> s;
inline int Max(int a,int b) {return a>b?a:b;}
int ans=0;
void work(int i){
while(!s.empty()) s.pop();
node u;u.pos=0,u.height=0;s.push(u);
s.push(u);
for(int j=1;j<=m;++j){
while(s.size()>1&&a[i][j]<=s.top().height) s.pop();
ans=Max(ans,(j-s.top().pos)*a[i][j]);
node u;u.pos=j,u.height=a[i][j];
s.push(u);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
if(mp[i][j]) a[i][j]=a[i-1][j]+mp[i][j];
else a[i][j]=0;
}
}
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",a[i][j]);
printf("\n");
}*/
for(int i=1;i<=n;i++) work(i);
printf("%d\n",ans);
return 0;
}