zoukankan      html  css  js  c++  java
  • P2216 [HAOI2007]理想的正方形 (单调队列)

    题目链接:P2216 [HAOI2007]理想的正方形

    题目描述

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

    输入格式

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

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

    输出格式

    仅一个整数,为 (a imes b)矩阵中所有“ (n imes 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

    思路

    单调队列

    二维 RMQ 问题。

    设原矩阵为 m[][],用单调队列求每行的最大/最小值,分别存入两个矩阵 maxr[][] 和 minr[][]。maxr[i][j] 代表 m[i][j] 到 m[i][j + n - 1] 的最大值,minr[i][j] 代表 m[i][j] 到 m[i][j + n - 1] 的最小值。

    接下来对这两个矩阵用单调队列求每列的最大/最小值,分别存入两个矩阵 maxc[][] 和 minc[][]。maxr[i][j] 代表 m[i][j] 到 m[i + n - 1][j + n - 1] 的最大值,minr[i][j] 代表 m[i][j] 到 m[i + n - 1][j + n - 1] 的最小值。

    最后遍历 maxc[][] 和 minc[][] 即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1010;
    const int inf = 0x3f3f3f3f;
    
    int m[maxn][maxn];
    
    int maxr[maxn][maxn], maxc[maxn][maxn];
    int minr[maxn][maxn], minc[maxn][maxn];
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int a, b, n;
        cin >> a >> b >> n;
        for(int i = 1; i <= a; ++i) {
            for(int j = 1; j <= b; ++j) {
                cin >> m[i][j];
            }
        }
        for(int i = 1; i <= a; ++i) {
            int l = 1, r = 1;
            int L = 1, R = 1;
            int q1[maxn] = {0, l}, q2[maxn] = {0, L};
            for(int j = 2; j <= b; ++j) {
                while(r >= l && j - q1[l] >= n) ++l;
                while(r >= l && m[i][j] <= m[i][q1[r]]) --r;
                q1[++r] = j;
                if(j >= n) minr[i][j - n + 1] = m[i][q1[l]];
    
                while(R >= L && j - q2[L] >= n) ++L;
                while(R >= L && m[i][j] >= m[i][q2[R]]) --R;
                q2[++R] = j;
                if(j >= n) maxr[i][j - n + 1] = m[i][q2[L]];
            }
        }
    
        for(int i = 1; i <= b - n + 1; ++i) {
            int l = 1, r = 1;
            int L = 1, R = 1;
            int q1[maxn] = {0, l}, q2[maxn] = {0, L};
            for(int j = 2; j <= a; ++j) {
                while(r >= l && j - q1[l] >= n) ++l;
                while(r >= l && minr[j][i] <= minr[q1[r]][i]) --r;
                q1[++r] = j;
                if(j >= n) minc[j - n + 1][i] = minr[q1[l]][i];
    
                while(R >= L && j - q2[L] >= n) ++L;
                while(R >= L && maxr[j][i] >= maxr[q2[R]][i]) --R;
                q2[++R] = j;
                if(j >= n) maxc[j - n + 1][i] = maxr[q2[L]][i];
            }
        }
        int ans = inf;
        for(int i = 1; i <= a - n + 1; ++i) {
            for(int j = 1; j <= b - n + 1; ++j) {
                ans = min(ans, maxc[i][j] - minc[i][j]);
            }
        }
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    聊聊 print 的前世今生
    在树莓派里搭建 Lighttpd 服务器
    如何重复执行一条命令直至运行成功?
    手把手教你Windows Linux双系统的安装与卸载
    你以为只有马云会灌鸡汤?Linux 命令行也会!
    Linux 下三种提高工作效率的文件处理技巧
    太高效了!玩了这么久的Linux,居然不知道这7个终端快捷键!
    Linux下分析bin文件的10种方法
    Linux下几个与磁盘空间和文件尺寸相关的命令
    如何让你的脚本可以在任意地方都可执行?
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11494232.html
Copyright © 2011-2022 走看看