• 【HAOI2007】理想的正方形


    【问题描述】

    有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

    【输入】

    第一行为3个整数,分别表示a,b,n的值
    第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

    【输出】

    仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

    分析】

    单调队列,先处理横行,再处理竖行。

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstdio>
     5 #include <cstring>
     6 const int MAX=1010;
     7 const int INF=0x7fffffff;
     8 using namespace std;
     9 //注意Max与Min(i,j)代表第i行从 
    10 int data[MAX][MAX],Max[MAX][MAX],Min[MAX][MAX];
    11 int a,b,n,ans=INF;
    12 
    13 void init();//输入数据
    14 void solve();
    15 void prepare(int hang);
    16 void work(int lie);
    17 
    18 int main()
    19 {
    20     //文件操作
    21     freopen("square.in","r",stdin);
    22     freopen("square.out","w",stdout);
    23     init();//输入数据 
    24     solve();//求解 
    25     return 0;
    26 }
    27 void init()
    28 {
    29     scanf("%d%d%d",&a,&b,&n);
    30     for (int i=1;i<=a;i++)
    31     for (int j=1;j<=b;j++) 
    32     scanf("%d",&data[i][j]);
    33 }
    34 void solve()
    35 {
    36      //计算出每行各个元素的最大值与最小值 
    37      for (int i=1;i<=a;i++) prepare(i);//横推行 
    38     // printf("
    ");
    39      for (int i=n;i<=b;i++) work(i);//纵推列 
    40      printf("%d
    ",ans);
    41 }
    42 void prepare(int hang)
    43 {
    44      int Q_MAX[MAX],front_MAX=1,rear_MAX=1;
    45      int Q_MIN[MAX],front_MIN=1,rear_MIN=1;
    46      for (int i=1;i<=n;i++)//预处理 
    47      {
    48          while (front_MAX<rear_MAX && data[hang][Q_MAX[rear_MAX]]<data[hang][i]) rear_MAX--;
    49          Q_MAX[++rear_MAX]=i;
    50          while (front_MIN<rear_MIN && data[hang][Q_MIN[rear_MIN]]>data[hang][i]) rear_MIN--;
    51          Q_MIN[++rear_MIN]=i;
    52      }
    53      //开始计算,千万要注意边界问题 
    54      for (int i=n;i<=b;i++)
    55      {
    56          //先计算MAX与MIN值 
    57          while (front_MAX<rear_MAX && Q_MAX[front_MAX+1]<(i-n+1)) front_MAX++; 
    58          Max[hang][i]=data[hang][Q_MAX[front_MAX+1]];
    59          while (front_MIN<rear_MIN && Q_MIN[front_MIN+1]<(i-n+1)) front_MIN++; 
    60          Min[hang][i]=data[hang][Q_MIN[front_MIN+1]];
    61          //再考虑加入队列 
    62          while (front_MAX<rear_MAX && data[hang][Q_MAX[rear_MAX]]<data[hang][i+1]) rear_MAX--;
    63          Q_MAX[++rear_MAX]=i+1;         
    64          while (front_MIN<rear_MIN && data[hang][Q_MIN[rear_MIN]]>data[hang][i+1]) rear_MIN--;
    65          Q_MIN[++rear_MIN]=i+1;
    66      }
    67      //打印
    68      //for (int i=n;i<=b;i++) printf("(%d %d) ",Max[hang][i],Min[hang][i]);
    69     // printf("
    "); 
    70 } 
    71 void work(int lie)
    72 {
    73      //printf("%d:",lie);
    74      int Q_MAX[MAX],front_MAX=1,rear_MAX=1;
    75      int Q_MIN[MAX],front_MIN=1,rear_MIN=1;
    76      for (int i=1;i<=n;i++)//预处理,注意这里换成行了 
    77      {
    78          while (front_MAX<rear_MAX && Max[Q_MAX[rear_MAX-1]][lie]<Max[i][lie]) rear_MAX--;
    79          Q_MAX[rear_MAX++]=i;
    80          while (front_MIN<rear_MIN && Min[Q_MIN[rear_MIN-1]][lie]>Min[i][lie]) rear_MIN--;
    81          Q_MIN[rear_MIN++]=i;
    82      }
    83      //开始计算,千万要注意边界问题 
    84      for (int i=n;i<=a;i++)
    85      {
    86          while (front_MAX<rear_MAX && Q_MAX[front_MAX]<(i-n+1)) front_MAX++; 
    87          while (front_MIN<rear_MIN && Q_MIN[front_MIN]<(i-n+1)) front_MIN++; 
    88          ans=min(ans,Max[Q_MAX[front_MAX]][lie]-Min[Q_MIN[front_MIN]][lie]);
    89          
    90          //printf("(%d %d) ",Q_MAX[front_MAX],Q_MIN[front_MIN]);
    91          //再考虑加入队列 
    92          while (front_MAX<rear_MAX && Max[Q_MAX[rear_MAX-1]][lie]<Max[i+1][lie]) rear_MAX--;
    93          Q_MAX[rear_MAX++]=i+1;         
    94          while (front_MIN<rear_MIN && Min[Q_MIN[rear_MIN-1]][lie]>Min[i+1][lie]) rear_MIN--;
    95          Q_MIN[rear_MIN++]=i+1;
    96      }
    97      //printf("
    ");
    98 }
    View Code
  • 相关阅读:
    POJ 1509 Glass Beads【字符串最小表示法】
    Codeforces 665C Simple Strings【暴力,贪心】
    Codeforces 665D Simple Subset【构造】
    HDU 5667 Sequence【矩阵快速幂+费马小定理】
    Codeforces 667D World Tour【最短路+枚举】
    Codeforces 667D World Tour【最短路+枚举】
    HDU 5676 ztr loves lucky numbers【DFS】
    Codeforces 667C Reberland Linguistics【DFS】
    前端学习笔记三
    Datawhale编程——动态规划DP
  • 原文地址:https://www.cnblogs.com/hoskey/p/3746577.html
Copyright © 2020-2023  润新知