1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1402 Solved: 738
[Submit][Status]
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
Output
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
Sample Input
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1
问题规模
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
问题规模
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
HINT
题解:
真是一道好题!
我一开始只想到了二维的RMQ,分析了一下时间和空间复杂度,感觉都承受不起……
一看题解,恍然大悟,因为该问题的特殊性,固定了以n为边长,所以只要用单调队列即可,RMQ多余了,用不到RMQ的优点
(而且,我参看的大牛的代码很巧妙的使代码量降了下来,如下这是一种技巧,以后要掌握)
代码:
uses math;
var f:array[..,..,..] of longint;
g,c:array[..,..] of longint;
i,j,a,b,n,ans:longint;
procedure init;
begin
readln(a,b,n);
for i:= to a do
begin
for j:= to b do read(c[i,j]);
readln;
end;
end;
procedure work(x:longint);
var i,j,l,r:longint;
q:array[..] of longint;
begin
for i:= to a do
begin
fillchar(q,sizeof(q),);
l:=;r:=;
for j:= to b do
begin
while (l<=r) and (c[i,q[r]]<=c[i,j]) do dec(r);
inc(r);q[r]:=j;
while (l<r) and (q[l]<j-n+) do inc(l);
g[i,j]:=c[i,q[l]];
end;
end;
for i:= to b do
begin
fillchar(q,sizeof(q),);
l:=;r:=;
for j:= to a do
begin
while (l<=r) and (g[q[r],i]<=g[j,i]) do dec(r);
inc(r);q[r]:=j;
while (l<r) and (q[l]<j-n+) do inc(l);
f[x,j,i]:=g[q[l],i];
end;
end;
end;
procedure main;
begin
work();
for i:= to a do
for j:= to b do
c[i,j]:=-c[i,j];
work();
ans:=maxlongint;
for i:=n to a do
for j:=n to b do
ans:=min(ans,f[,i,j]+f[,i,j]);
writeln(ans);
end;
begin
init;
main;
end.