「BZOJ1047」[HAOI2007] 理想的正方形
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
题解:
首先考虑每一行长度为n的线段中的最小值最大值,利用单调队列a * b 的复杂度求出所有线段的min,max。然后将线段看成一个点,利用单调队列求出在同一列的n个点的min,max。总复杂度为:2 * a * b
#include <bits/stdc++.h> //#include <unordered_map> using namespace std; typedef long long ll; const int maxn = 1e3+10; const ll INF = (1e9); int a[maxn][maxn]; int q1[maxn],q2[maxn];//求max, 求min int minL[maxn][maxn],maxL[maxn][maxn]; int main(){ int n,m,r;scanf("%d%d%d",&n,&m,&r); for(int i = 1;i <= n;i++){ for(int j = 1;j <= m;j++){ scanf("%d",&a[i][j]); } } if(r == 1){ printf("0 ");return 0; } for(int i = 1;i <= n;i++){ int cnt = 0; int h1 = 0,t1 = 0,h2 = 0,t2 = 0; q1[t1++] = 1;q2[t2++] = 1; for(int j = 2;j <= m;j++){ while(h1 < t1 && q1[h1] + r - 1 < j)h1++; while(h1 < t1 && a[i][j] >= a[i][q1[t1 - 1]])t1--; q1[t1++] = j; while(h2 < t2 && q2[h2] + r - 1 < j)h2++; while(h2 < t2 && a[i][j] <= a[i][q2[t2 - 1]])t2--; q2[t2++] = j; if(j - r >= 0){ maxL[i][++cnt] = a[i][q1[h1]]; minL[i][cnt] = a[i][q2[h2]]; } } } /*for(int i = 1;i <= n;i++){ for(int j = 1;j + r - 1 <= m;j++){ printf("i = %d j = %d minL = %d maxL = %d ",i,j,minL[i][j],maxL[i][j]); } }*/ int ans = INF; for(int i = 1;i + r - 1 <= m;i++){ int h1 ,t1, h2, t2; h1 = h2 = t1 = t2 = 0; q1[t1++] = 1;q2[t2++] = 1; for(int j = 2;j <= n;j++){ while(h1 < t1 && q1[h1] + r - 1 < j)h1++; while(h1 < t1 && maxL[q1[t1 - 1]][i] <= maxL[j][i])t1--; q1[t1++] = j; while(h2 < t2 && q2[h2] + r - 1 < j)h2++; while(h2 < t2 && minL[q2[t2 - 1]][i] >= minL[j][i])t2--; q2[t2++] = j; if(j - r >= 0)ans = min(ans,maxL[q1[h1]][i] - minL[q2[h2]][i]); } } printf("%d ",ans); return 0; }