题目大意
解题思路
枚举左右边界,压成一维做前缀和,维护一个单调递减的栈,从后往前做,对答案有贡献的是小于它的最前点,如果比上一个大则继续退栈,比上一个小则不可能对答案贡献,因为和它匹配的点序号更大,区间长度更小。
code
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define max(n1,n2) ((n1>n2)?n1:n2)
#define min(n1,n2) ((n1>n2)?n2:n1)
#define num(n1,n2) ((n1-1)*3*n+n2+1)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=300,inf=2147483647;
int n,m,l,r;LL x,s[maxn+10][maxn+10],sum[maxn+10],a[maxn+10],b[maxn+10];
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)
fo(j,1,m)
scanf("%lld",&x),s[i][j]=s[i][j-1]+x;
LL ans=1;
fo(i,0,m)
fo(j,i+1,m){
a[0]=0;
fo(k,1,n){
sum[k]=sum[k-1]+s[k][j]-s[k][i];
if(sum[k]<a[a[0]])a[++a[0]]=sum[k],b[a[0]]=k;
}
fd(k,n,1)
if(a[a[0]]<sum[k]){
for(;a[0]&&(a[a[0]-1]<sum[k]);a[0]--);
ans=max(ans,(k-b[a[0]])*(j-i));
}
}
printf("%lld",ans);
return 0;
}