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
HINT
问题规模
(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<=10
Source
一个典型的单调队列dp,枚举矩阵左端,下端利用单调队列一路扫过,复杂度O(n2)。
我的代码不知道为什么神慢无比,险些TLE,仅供参考。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 using namespace std; 5 6 #define inf (2000000000) 7 #define maxn 1010 8 int a,b,n,s[maxn][maxn],ans = inf; 9 10 inline int read() 11 { 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 18 struct node { int h,key; }q1[maxn*maxn],q2[maxn*maxn]; 19 20 inline void work() 21 { 22 int h1,t1,h2,t2; 23 int lef,rig,up,down; 24 for (lef = 1;lef+n-1 <= b;++lef) 25 { 26 rig = lef+n-1; up = 1; down = n; 27 h1 = t1 = h2 = t2 = 0; 28 for (int i = up;i <= down;++i) 29 for (int j = lef;j <= rig;++j) 30 { 31 while (h1 < t1 && s[i][j] <= q1[t1].key) --t1; 32 q1[++t1] = (node){i,s[i][j]}; 33 while (h2 < t2 && s[i][j] >= q2[t2].key) --t2; 34 q2[++t2] = (node){i,s[i][j]}; 35 } 36 ans = min(ans,q2[h2+1].key - q1[h1+1].key); 37 for (++down,++up;down <= a;++down,++up) 38 { 39 while (q1[h1+1].h < up) ++h1; 40 while (q2[h2+1].h < up) ++h2; 41 for (int i = lef;i <= rig;++i) 42 { 43 while (h1 < t1 && s[down][i] <= q1[t1].key) --t1; 44 q1[++t1] = (node){down,s[down][i]}; 45 while (h2 < t2 && s[down][i] >= q2[t2].key) --t2; 46 q2[++t2] = (node){down,s[down][i]}; 47 } 48 ans = min(ans,q2[h2+1].key - q1[h1+1].key); 49 } 50 } 51 } 52 53 int main() 54 { 55 a = read(); b = read(); n = read(); 56 for (int i = 1;i <= a;++i) for (int j = 1;j <= b;++j) s[i][j] = read(); 57 work(); 58 printf("%d",ans); 59 return 0; 60 }