[HAOI2007,P2216,BZOJ1047]理想的正方形单调队列解法

题目描述

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

输入格式

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

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

输出格式

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

\(20\%\) 的数据 \(2 \le a,b \le 100,n \le a,n \le b,n \le 10\)

\(100\%\) 的数据 \(2 \le a,b \le 1000,n \le a,n \le b,n \le 100\)

代码展示

一看就是单调队列

#include <iostream>
#include <deque>
using namespace std;

const int N = 1024;

int G[N][N];

deque<pair<int, int>> _maxn;
deque<pair<int, int>> _minn;

int maxn[N][N];
int minn[N][N];

int maxn2[N][N];
int minn2[N][N];

int ans_max[N][N];
int ans_min[N][N];

int main()
{
    int a, b, n;
    cin >> a >> b >> n;
    for (int i = 1; i <= a; i++)
    {
        for (int j = 1; j <= b; j++)
        {
            cin >> G[i][j];
        }
    }
    for (int i = 1; i <= a; i++)
    {
        for (int j = 1; j <= b; j++)
        {
            while (!_maxn.empty() && _maxn.front().second <= j - n)
                _maxn.pop_front();
            while (!_minn.empty() && _minn.front().second <= j - n)
                _minn.pop_front();
            while (!_maxn.empty() && _maxn.back().first < G[i][j])
                _maxn.pop_back();
            while (!_minn.empty() && _minn.back().first > G[i][j])
                _minn.pop_back();
            _maxn.push_back(make_pair(G[i][j], j));
            _minn.push_back(make_pair(G[i][j], j));

            if (j >= n)
            {
                maxn[i][j] = _maxn.front().first;
                minn[i][j] = _minn.front().first;
            }
        }
        _maxn.clear();
        _minn.clear();
    }
    for (int i = n; i <= b; i++)
    {
        for (int j = 1; j <= a; j++)
        {
            while (!_maxn.empty() && _maxn.front().second <= j - n)
                _maxn.pop_front();
            while (!_minn.empty() && _minn.front().second <= j - n)
                _minn.pop_front();
            while (!_maxn.empty() && _maxn.back().first < maxn[j][i])
                _maxn.pop_back();
            while (!_minn.empty() && _minn.back().first > minn[j][i])
                _minn.pop_back();
            _maxn.push_back(make_pair(maxn[j][i], j));
            _minn.push_back(make_pair(minn[j][i], j));

            if (j >= n)
            {
                ans_max[j][i] = _maxn.front().first;
                ans_min[j][i] = _minn.front().first;
            }
        }
        _maxn.clear();
        _minn.clear();
    }
    int ans = 0x3f3f3f3f;
    for (int i = n; i <= a; i++)
        for (int j = n; j <= b; j++)
            ans = min(ans, ans_max[i][j] - ans_min[i][j]);
    cout << ans;
    return 0;
}
posted @ 2021-09-09 13:37  Icys  阅读(64)  评论(0编辑  收藏  举报