题目描述
Description
Hzgd神牛准备给自己盖一座很华丽的宫殿。于是,他看中了一块N*M的矩形空地。空地中每个格子都有自己的海拔高度。胡张想让他的宫殿的平均海拔在海平面之上(假设海平面的高度是0,平均数都会算吧?)。而且,胡张希望他的宫殿是个矩形且尽量大,能够容纳更多的人来膜拜他。请问胡张的宫殿最后会有多大?
Input Format
第一行为N和M。之后N行,每行M个数,描述的空地的海拔。
Output Format
输出一行,表示宫殿最大面积。
Sample Input
3 2
4 0
-10 8
-2 -2
Sample Output
4
Data Limit
对于30%的数据,N,M≤50;
对于100%的数据,N,M≤200;
被坑惨了……不开longlong就爆蛋开了longlong马上AC
做了今年noip初赛的最后一题之后顿时觉得这题不难
首先预处理出每一行的前缀和,用rowsum[i][j]表示第i行前j个数的和
然后枚举子矩阵的纵坐标的起始点和结束点,问题转化为求一个序列中最长的和>=0的子串的长度
先算出序列中所有长度的前缀和,然后记录下原来的位置直接排序一下
那么新的有序序列中前缀和是递增的
考虑从l到r的子串何时能更新最大值:
当sum[r]-sum[l-1]>=0且l<=r时才可以
排序之后保证了sum数组的不降性质,因此只需要原来保存的rank也满足不降就可以更新答案了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 598460606
#define pa pair<int,int>
#define pi 3.1415926535897932384626433832795028841971
#define N 1000
using namespace std;
struct aaa{
LL rnk,x;
}b[1000];
bool operator < (const aaa &a,const aaa &b)
{return a.x<b.x||a.x==b.x&&a.rnk<b.rnk;}
inline LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m;
LL rowsum[N][N],ans;
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
rowsum[i][j]=rowsum[i][j-1]+read();
for (int i=1;i<=m;i++)
for(int j=i;j<=m;j++)
{
LL sum=0;
b[0].x=0;b[0].rnk=0;
for (int k=1;k<=n;k++)
{
sum+=rowsum[k][j]-rowsum[k][i-1];
b[k].x=sum;
b[k].rnk=k;
}
sort(b,b+n+1);
LL mn=b[0].rnk,l=(j-i+1);
for(int k=0;k<=n;k++)
{
if(b[k].rnk>mn)ans=max(ans,l*(b[k].rnk-mn));
mn=min(mn,b[k].rnk);
}
}
printf("%lld\n",ans);
}