题目:Bzoj1047
题解:
首先,对于每行长度为n的区间求出RMQ,再每一列求出先前求出每一行的RMQ的RMQ,这样做相当于求出了边长为n的正方形的RMQ,用正方形的左上角记录,枚举左上角的坐标求解。
求长度为n的区间的RMQ时可以用单调队列,时间复杂的为O(n)。
代码:
program pro;
var
map:array[0..1005,0..1005]of longint;
zx,zy:array[0..1005,0..1005]of record max,min:longint; end;
que,que1,time,time1:array[0..10000]of longint;
ans,a,b,n,i,j,l,r,h,h1,t,t1,tt:longint;
procedure openf;
begin
assign(input,'square.in'); reset(input);
assign(output,'square.out'); rewrite(output);
end;
procedure closef;
begin
close(input);
close(output);
end;
begin
openf;
readln(a,b,n);
for i:=1 to a do
for j:=1 to b do read(map[i,j]);
for i:=1 to a do
begin
h:=1; t:=0;
h1:=1; t1:=0;
fillchar(que,sizeof(que),0);
fillchar(que1,sizeof(que1),0);
for j:=1 to n do
begin
while (t>=h)and(map[i,j]>que[t]) do dec(t);
inc(t); que[t]:=map[i,j]; time[t]:=j;
while (t1>=h1)and(map[i,j]<que1[t1]) do dec(t1);
inc(t1); que1[t1]:=map[i,j]; time1[t1]:=j;
end;
for l:=1 to b-n+1 do
begin
r:=l+n-1;
while (t>=h)and(que[t]<map[i,r]) do dec(t);
inc(t); que[t]:=map[i,r]; time[t]:=r;
while (t1>=h1)and(que1[t1]>map[i,r]) do dec(t1);
inc(t1); que1[t1]:=map[i,r]; time1[t1]:=r;
while time[h]<l do inc(h);
zx[i,l].max:=que[h];
while time1[h1]<l do inc(h1);
zx[i,l].min:=que1[h1];
end;
end;
for i:=1 to b-n+1 do
begin
h:=1; t:=0;
h1:=1; t1:=0;
fillchar(que,sizeof(que),0);
fillchar(que1,sizeof(que1),0);
for j:=1 to n do
begin
while (t>=h)and(zx[j,i].max>que[t]) do dec(t);
inc(t); que[t]:=zx[j,i].max; time[t]:=j;
while (t1>=h1)and(zx[j,i].min<que1[t1]) do dec(t1);
inc(t1); que1[t1]:=zx[j,i].min; time1[t1]:=j;
end;
for l:=1 to a-n+1 do
begin
r:=l+n-1;
while (t>=h)and(que[t]<zx[r,i].max) do dec(t);
inc(t); que[t]:=zx[r,i].max; time[t]:=r;
while (t1>=h1)and(que1[t1]>zx[r,i].min)do dec(t1);
inc(t1); que1[t1]:=zx[r,i].min; time1[t1]:=r;
while time[h]<l do inc(h);
zy[l,i].max:=que[h];
while time1[h1]<l do inc(h1);
zy[l,i].min:=que1[h1];
end;
end;
ans:=maxlongint;
for i:=1 to a-n+1 do
for j:=1 to b-n+1 do
if zy[i,j].max-zy[i,j].min<ans then ans:=zy[i,j].max-zy[i,j].min;
writeln(ans);
closef;
end.