[HAOI2007]理想的正方形

标签: 单调队列


题目描述

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

输入格式:

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

输出格式:

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

输入样例#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

分析

  先枚举正方形所在的行,确定行之后,用滑动窗口分别求出窗口中的最大和最小值.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=1050;
const int inf=0x3f3f3f3f;
int s[maxn][maxn],a,b,n;
struct Queue
{
    int q[maxn],t,h;
    Queue(){
        t=0,h=1;
    }
    void push(int x,int y,int f=1){
        while(t-h+1>=1&&s[q[t]][y]*f>=s[x][y]*f) t--;
        q[++t]=x;
    }
    void pop(int x){
        while(t-h+1>=1&&q[h]<x) h++;
    }
    int top(){
        return q[h];
    }
}m[maxn],M[maxn];

int main(int argc, char const *argv[])
{
    scanf("%d%d%d", &a,&b,&n);
    for (int i = 0; i < a; ++i)
    {
        for (int j = 0; j < b; ++j)
        {
            scanf("%d", &s[i][j]);
        }
    }
    int ans=inf;
    for (int i = 0; i+n <= a; ++i)
    {
        if(i==0)
            for (int j = 0; j < b; ++j)
            {
                for (int k = 0; k < n; ++k)
                {
                    m[j].push(k,j);
                    M[j].push(k,j,-1);
                }
            }
        else
            for (int j = 0; j < b; ++j)
            {
                m[j].pop(i),m[j].push(i+n-1,j);
                M[j].pop(i),M[j].push(i+n-1,j,-1);
            }
        int h=1,t=0,X[maxn],Y[maxn];
        int hh=1,tt=0,XX[maxn],YY[maxn];
        for (int j = 0; j+n <= b; ++j)
        {
            if(j==0){
                for (int k = j; k < j+n; ++k)
                {
                    int x=m[k].top();
                    while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][k]) t--;
                    X[++t]=x,Y[t]=k;

                    x=M[k].top();
                    while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][k]) tt--;
                    XX[++tt]=x,YY[tt]=k;
                }
            }
            else{
                int x=m[j+n-1].top();
                while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][j+n-1]) t--;
                X[++t]=x,Y[t]=j+n-1;

                x=M[j+n-1].top();
                while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][j+n-1]) tt--;
                XX[++tt]=x,YY[tt]=j+n-1;
            }
            while(Y[h]<j) h++;
            while(YY[hh]<j) hh++;
            ans=min(ans,s[XX[hh]][YY[hh]]-s[X[h]][Y[h]]);
        }
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sciorz/p/9050549.html