1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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的优点
(而且,我参看的大牛的代码很巧妙的使代码量降了下来,如下这是一种技巧,以后要掌握)
代码:
1 uses math; 2 var f:array[1..2,0..1100,0..1100] of longint; 3 g,c:array[0..1100,0..1100] of longint; 4 i,j,a,b,n,ans:longint; 5 procedure init; 6 begin 7 readln(a,b,n); 8 for i:=1 to a do 9 begin 10 for j:=1 to b do read(c[i,j]); 11 readln; 12 end; 13 end; 14 procedure work(x:longint); 15 var i,j,l,r:longint; 16 q:array[0..1500] of longint; 17 begin 18 for i:=1 to a do 19 begin 20 fillchar(q,sizeof(q),0); 21 l:=1;r:=0; 22 for j:=1 to b do 23 begin 24 while (l<=r) and (c[i,q[r]]<=c[i,j]) do dec(r); 25 inc(r);q[r]:=j; 26 while (l<r) and (q[l]<j-n+1) do inc(l); 27 g[i,j]:=c[i,q[l]]; 28 end; 29 end; 30 for i:=1 to b do 31 begin 32 fillchar(q,sizeof(q),0); 33 l:=1;r:=0; 34 for j:=1 to a do 35 begin 36 while (l<=r) and (g[q[r],i]<=g[j,i]) do dec(r); 37 inc(r);q[r]:=j; 38 while (l<r) and (q[l]<j-n+1) do inc(l); 39 f[x,j,i]:=g[q[l],i]; 40 end; 41 end; 42 end; 43 procedure main; 44 begin 45 work(1); 46 for i:=1 to a do 47 for j:=1 to b do 48 c[i,j]:=0-c[i,j]; 49 work(2); 50 ans:=maxlongint; 51 for i:=n to a do 52 for j:=n to b do 53 ans:=min(ans,f[1,i,j]+f[2,i,j]); 54 writeln(ans); 55 end; 56 begin 57 init; 58 main; 59 end.