• 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
    ");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;
    }
  • 相关阅读:
    Fractions Again?! UVA
    Maximum Product UVA
    Investigating Div-Sum Property UVA
    Period UVALive
    Numbers That Count POJ
    Orders POJ
    小明的数列
    Spreading the Wealth uva 11300
    Play on Words UVA
    第二百七十天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/cleanerhgf/p/12088476.html
Copyright © 2020-2023  润新知