题目描述
AP 神牛准备给自己盖一座很华丽的宫殿。于是,他看中了一块N*M 的矩形空地。
空地中每个格子都有自己的海拔高度。AP 想让他的宫殿的平均海拔在海平面之上(假设
海平面的高度是0,平均数都会算吧?)。而且,AP 希望他的宫殿尽量大,能够容纳更
多的人来膜拜他。请问AP 的宫殿最后会有多大?
输入输出格式
输入格式:
第一行为N 和M。之后N 行,每行M 个数,描述的空地的海拔。
输出格式:
输出一行,表示宫殿最大面积。
输入输出样例
输入样例#1:
3 2
4 0
-10 8
-2 -2
输出样例#1:
4
分析:
dp+单调栈。
这道题很像最大子矩阵。但是是求面积大于0的最大子矩阵。我们考虑像普通求法一样枚举左右边界,用前缀和表示1~i行的总和。后面画图可知单调栈的操作。
代码:
var
n,m,ans,top:int64;
e:int64;
f:array [0..202] of int64;
stack:array [0..202] of int64;
sum:array [0..202,0..202] of int64;
procedure init;
var x,i,j:longint;
begin
readln(n,m);
for i:=1 to n do
for j:=1 to m do
begin
read(x);
sum[i,j]:=sum[i,j-1]+x;
end;
end;
function max(x,y:int64):int64;
begin
if x>y then exit(x)
else exit(y);
end;
function erf(x:int64):int64;
var l,r,mid,w:longint;
begin
l:=1; r:=top; w:=-1;
while l<=r do
begin
mid:=(l+r) shr 1;
if stack[mid]<x then begin w:=mid; r:=mid-1; end
else l:=mid+1;
end;
exit(w);
end;
procedure dp;
var i,j,k:longint;
a,w:int64;
begin
for i:=1 to m do
for j:=i to m do
begin
e:=0; stack[0]:=maxlongint; top:=0;
for k:=1 to n do
begin
a:=sum[k,j]-sum[k,i-1];
e:=e+a;
if e>0 then ans:=max(ans,k*(j-i+1))
else
begin
w:=erf(e);
if (w<>-1) then ans:=max(ans,(k-f[w])*(j-i+1));
end;
if e<stack[top] then
begin
inc(top);
stack[top]:=e;
f[top]:=k;
end;
end;
end;
end;
begin
init;
dp;
writeln(ans);
end.