BZOJ 1047

「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

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

题解:

首先考虑每一行长度为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\n");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\n",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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cleanerhgf/p/12088476.html