Luogu2216 [HAOI2007]理想的正方形

原题链接:https://www.luogu.com.cn/problem/P2216

理想的正方形

题目描述

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

输入格式

第一行为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

题解

二维的滑动窗口,先对每一行做一次横向的滑动窗口,求出每一行长为 n n n的窗口滑过的最小/大值,再对求出的最小/大值做一次纵向的滑动窗口,这样求出的就是二维的 n × n n\times n n×n的窗口覆盖的最小/大值。

代码

看起来多,实际上都是复制粘贴的,一遍过针不戳。

#include
using namespace std;
const int M=1e3+5;
int n,a,b,que[M],sqr[M][M],mn[M][M],mx[M][M],mn2[M][M],mx2[M][M],head,tail;
void hori(int x)
{
     
    que[head=tail=1]=1;if(n==1)mn[x][1]=sqr[x][1];
    for(int i=2;i<=b;++i)
    {
     
        for(;sqr[x][que[tail]]>=sqr[x][i]&&tail>=head;--tail);
        que[++tail]=i;
        for(;i-que[head]+1>n&&head<=tail;++head);
        if(i>=n)mn[x][i]=sqr[x][que[head]];
    }
    que[head=tail=1]=1;if(n==1)mx[x][1]=sqr[x][1];
    for(int i=2;i<=b;++i)
    {
     
        for(;sqr[x][que[tail]]<=sqr[x][i]&&tail>=head;--tail);
        que[++tail]=i;
        for(;i-que[head]+1>n&&head<=tail;++head);
        if(i>=n)mx[x][i]=sqr[x][que[head]];
    }
}
void verti(int x)
{
     
    que[head=tail=1]=1;if(n==1)mn2[1][x]=mn[1][x];
    for(int i=2;i<=a;++i)
    {
     
        for(;mn[que[tail]][x]>=mn[i][x]&&tail>=head;--tail);
        que[++tail]=i;
        for(;i-que[head]+1>n&&head<=tail;++head);
        if(i>=n)mn2[i][x]=mn[que[head]][x];
    }
    que[head=tail=1]=1;if(n==1)mx2[1][x]=mx[1][x];
    for(int i=2;i<=a;++i)
    {
     
        for(;mx[que[tail]][x]<=mx[i][x]&&tail>=head;--tail);
        que[++tail]=i;
        for(;i-que[head]+1>n&&head<=tail;++head);
        if(i>=n)mx2[i][x]=mx[que[head]][x];
    }
}
void in()
{
     
    scanf("%d%d%d",&a,&b,&n);
    for(int i=1;i<=a;++i)for(int j=1;j<=b;++j)scanf("%d",&sqr[i][j]);
}
void ac()
{
     
    for(int i=1;i<=a;++i)hori(i);
    for(int i=n;i<=b;++i)verti(i);
    int ans=INT_MAX;
    for(int i=n;i<=a;++i)for(int j=n;j<=b;++j)ans=min(ans,mx2[i][j]-mn2[i][j]);
    printf("%d\n",ans);
}
int main()
{
     
    in(),ac();
    system("pause");
}

你可能感兴趣的:(数据结构)