枚举上下界和右边界,用set记录左边界,set的insert理论上lgn级别的为啥会超时呢
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long LL;
const int N = 1010;
LL sum[N][N];
int mtx[N][N];
int n,m;
set<pair<LL,int>,greater<pair<LL,int>>> S;
LL getsum(int x1,int y1,int x2,int y2)
{
return sum[x2][y2] + sum[x1-1][y1-1] - sum[x2][y1-1] - sum[x1-1][y2];
}
int main(void)
{
scanf("%d%d",&n,&m);
memset(sum,0,sizeof sum);
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
scanf("%d",&mtx[i][j]);
}
}
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=m;j++)
{
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + mtx[i-1][j-1];
}
}
//枚举三个边界
LL ans = -1;
for(int i = 1;i<=n;i++)//上边界
{
for(int j = i;j<=n;j++)//下边界
{
S.clear();
S.insert({0,0});
for(int k = 1;k <= m;k++)//右边界
{
//查找右边界的最大值 sum k >= sum m 的m最小值
LL sumk = getsum(i,1,j,k);
//printf("行%d->行%d 列%d->列%d sum = %d\n",i,j,1,k,sumk);
auto it = S.lower_bound({sumk,0});//第一个小于等于sumk的
auto preit = it;
if(it->second == sumk) ++it;
if(it != S.end())
{
//printf("ans更新 (%d,%d,%d,%d) %lld\n",i,j,it->second,k,(LL)(j - i + 1) * (k - it->second));
ans = max(ans,(LL)(j - i + 1) * (k - it->second));
}
auto nxit = S.lower_bound({sumk,0});
if(nxit != S.end()&&nxit->second <= k) continue;
while(preit != S.begin() && preit->second >= k)
{
it = preit;
--preit;
S.erase(it);
}
if(preit == S.begin() && preit->second >= k) S.erase(preit);
S.insert({sumk,k});
}
}
}
printf("%lld",ans);
return 0;
}