首页 > 代码库 > HAOI2007 理想的正方形

HAOI2007 理想的正方形

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

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

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    begin10     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  begin18  for i:=1 to a do19   begin20    fillchar(q,sizeof(q),0);21    l:=1;r:=0;22    for j:=1 to b do23     begin24     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 do31   begin32    fillchar(q,sizeof(q),0);33    l:=1;r:=0;34    for j:=1 to a do35     begin36     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  begin45  work(1);46  for i:=1 to a do47   for j:=1 to b do48    c[i,j]:=0-c[i,j];49  work(2);50  ans:=maxlongint;51  for i:=n to a do52   for j:=n to b do53    ans:=min(ans,f[1,i,j]+f[2,i,j]);54  writeln(ans);55  end;56 begin57  init;58  main;59 end.
View Code