题目描述
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 ",ans); }