• luogu 2216 理想的正方形


    题目描述

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

    输入格式

    第一行为3个整数,分别表示a,b,n的值

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

    输出格式

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

    输入输出样例

    输入 #1
    5 4 2
    1 2 5 6
    0 17 16 0
    16 17 2 1
    2 10 2 1
    1 2 2 2
    
    输出 #1
    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

    分析

    直接暴力O(a*b*n*n),想办法优化

    我们发现正方形的边长固定,要在这个固定的区间中找最小值与最大值的最小差

    固定区间,嗯,考虑考虑单调队列?

    (虽说其他的数据结构也可以)

    既然是二维的,怎么实现呢,单调队列可是线性的

    这个好办,先处理行,再用行的结果处理列就好

    怎么想到呢

    我们分析自己的暴力程序,发现在处理最大最小值时做了很多无用功

    这根线性的题分析是一样的

    处理最大最小值有单调队列优化

    先处理行:

    根据行的结论处理列:

    好啦

    代码

      1 /***********************
      2 User:Mandy.H.Y
      3 Language:c++
      4 Problem:luogu 2216
      5 Algorithm:
      6 Date:2019.9.4 
      7 ***********************/
      8 
      9 #include<bits/stdc++.h>
     10 
     11 using namespace std;
     12 
     13 const int maxn = 1005;
     14 
     15 int n,m,l;
     16 int a[maxn][maxn];
     17 int l1,r1,l2,r2;
     18 int q1[maxn],q2[maxn];
     19 int mx1[maxn][maxn],mx2[maxn][maxn];
     20 int my1[maxn][maxn],my2[maxn][maxn];
     21 
     22 template<class T>inline void read(T &x){
     23     x = 0;bool flag = 0;char ch = getchar();
     24     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
     25     while(isdigit(ch)) x = (x << 1) + (x <<3) + (ch ^ 48),ch = getchar();
     26     if(flag) x = -x;
     27 }
     28 
     29 template<class T>void putch(const T x){
     30     if(x > 9) putch(x / 10);
     31     putchar(x % 10 | 48);
     32 }
     33 
     34 template<class T>void put(const T x){
     35     if(x < 0) putchar('-'),putch(-x);
     36     else putch(x);
     37 }
     38 
     39 void file(){
     40     freopen("2216.in","r",stdin);
     41 //    freopen("2216.out","w",stdout);
     42 }
     43 
     44 void readdata(){
     45     read(n);read(m);read(l);
     46     for(int i = 1; i <= n; ++ i)
     47         for(int j = 1;j <= m; ++ j)
     48             read(a[i][j]);
     49 }
     50 
     51 void work(){
     52     //
     53     for(int i = 1;i <= n; ++ i){
     54         l1 = r1 = 0;
     55         l2 = r2 = 0;
     56         for(int j = 1;j <= m; ++ j){
     57             
     58             while(l1 < r1 && (q1[l1] <= j - l)) l1++;
     59             while(l2 < r2 && (q2[l2] <= j - l)) l2++;
     60             
     61             while(l1 < r1 && a[i][j] >= a[i][q1[r1 - 1]]) r1 --;
     62             while(l2 < r2 && a[i][j] <= a[i][q2[r2 - 1]]) r2 --;
     63             
     64             q1[r1 ++ ] = j;
     65             q2[r2 ++ ] = j;
     66             
     67             if(l1 < r1) mx1[i][j] = a[i][q1[l1]];//第i行j-l+1~j的最大值 
     68             if(l2 < r2) mx2[i][j] = a[i][q2[l2]];//第i行j-l+1~j的最小值 
     69             //这个放在队列更新后,因为包括自身 
     70             //注意要存值而不是编号
     71             //处理列的时候可以用到 
     72         }
     73     }
     74     //
     75     for(int i = 1;i <= m; ++ i){
     76         l1 = r1 = 0;
     77         l2 = r2 = 0;
     78         for(int j = 1;j <= n; ++ j){
     79             
     80             while(l1 < r1 && (q1[l1] <= j - l)) l1++;
     81             while(l2 < r2 && (q2[l2] <= j - l)) l2++;
     82             
     83             
     84             while(l1 < r1 && mx1[j][i] >= mx1[q1[r1 - 1]][i]) r1 --;
     85             while(l2 < r2 && mx2[j][i] <= mx2[q2[r2 - 1]][i]) r2 --;
     86             //直接用行的结果
     87             //可以直接处理出以(i,j)为右下角顶点的n*n的最大值与最小值 
     88             q1[r1 ++ ] = j;
     89             q2[r2 ++ ] = j;
     90             
     91             if(l1 < r1) my1[j][i] = mx1[q1[l1]][i];//最大值 
     92             if(l2 < r2) my2[j][i] = mx2[q2[l2]][i];//最小值 
     93             
     94         }
     95     }
     96     int ans = 2e9;
     97     for(int i = l;i <= n; ++ i)
     98         for(int j = l;j <= m; ++ j){
     99             ans = min(ans,my1[i][j] - my2[i][j]);
    100         }
    101     put(ans);
    102 }
    103 
    104 int main(){
    105 //    file();
    106     readdata();
    107     work();
    108     return 0;
    109 }
    View Code
  • 相关阅读:
    流程控制
    数据类型和运算符
    抽奖
    蓝桥杯 第五届
    python下编译py成pyc和pyo
    Django中提示TemplateDoesNotExist?
    Ubuntu16.04 apache2 wsgi 部署django
    Ubuntu 14.04下Django+MySQL安装部署全过程
    LVM原理及PV、VG、LV、PE、LE关系图
    SQLServer2008-镜像数据库实施手册(双机)SQL-Server2014同样适用
  • 原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11457578.html
Copyright © 2020-2023  润新知