[BZOJ1047] [HAOI2007]理想的正方形

题目描述

Description

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

Input

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

Output

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

Sample Input

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

Sample Output

1

题目分析

单调队列= =
先预处理出对于每列 每个点向上n个点的最大最小值
然后在对于每一行的每n个点跑单调队列就好了

#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int a,b,n;
int v[1010][1010];
int minn[1010][1010],maxx[1010][1010];
int qmax[1010],qmin[1010],l1,l2,r1,r2;
int main()
{
    scanf("%d%d%d",&a,&b,&n);
    for(int i=1;i<=a;i++)
        for(int j=1;j<=b;j++)
            scanf("%d",&v[i][j]);
    for(int i=1;i<=a;i++)
    {
        l1=l2=1,r1=r2=0;
        for(int j=1;j<n;j++)
        {
            while(l1<=r1&&v[i][j]>=v[i][qmax[r1]]) r1--;
            qmax[++r1]=j;
            while(l2<=r2&&v[i][j]<=v[i][qmin[r2]]) r2--;
            qmin[++r2]=j;
        }
        for(int j=n;j<=b;j++)
        {
            while(l1<=r1&&v[i][j]>v[i][qmax[r1]]) r1--;
            while(l1<=r1&&qmax[l1]<=j-n) l1++;
            qmax[++r1]=j,maxx[i][j]=v[i][qmax[l1]];
            while(l2<=r2&&v[i][j]<v[i][qmin[r2]]) r2--;
            while(l2<=r2&&qmin[l2]<=j-n) l2++;
            qmin[++r2]=j,minn[i][j]=v[i][qmin[l2]];
        }
    }
    int ans=0x7f7f7f7f;
    for(int j=n;j<=b;j++)
    {
        l1=1,l2=1,r1=0,r2=0;
        for(int i=1;i<=a;i++)
        {   
            while(l1<=r1&&maxx[qmax[r1]][j]<=maxx[i][j]) r1--;
            while(l1<=r1&&qmax[l1]<=i-n) l1++;
            qmax[++r1]=i;
            while(l2<=r2&&minn[qmin[r2]][j]>=minn[i][j]) r2--;
            while(l2<=r2&&qmin[l2]<=i-n) l2++;
            qmin[++r2]=i;
            if(i>=n) ans=min(ans,maxx[qmax[l1]][j]-minn[qmin[l2]][j]);
        }
    }
    printf("%d",ans);
}

发表评论

邮箱地址不会被公开。 必填项已用*标注