理想的正方形

https://loj.ac/problem/10182

题目描述

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

思路

  我们可以先想办法把题目简单化,显然我们可以用单调队列一遍扫过去求出以\(i\)为左端点的连续的\(n\)个数的最大值和最小值,再考虑在列上思考,类似的,我们可以在求出来的最大和最小值的矩阵内按列\(dp\),求出\(n\)列中的最值,这也可以一遍实现,这样复杂度为\(O(ab)\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;

int read()
{
    int res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res*w;
}

int mp[N][N],f_max[N][N],f_min[N][N],f[N][N];
int q[N];
int main()
{
    int a=read(),b=read(),n=read();
    for(int i=1;i<=a;i++)
        for(int j=1;j<=b;j++)
            mp[i][j]=read();
    int head=0,tail=0;
    for(int i=1;i<=a;i++)
    {
        head=1,tail=0;
        for(int j=1;j<=b;j++)
        {
            while(head<=tail&&j-q[head]>=n)head++;
            while(head<=tail&&mp[i][q[tail]]>=mp[i][j])tail--;
            q[++tail]=j;
            if(j>=n)f[i][j-n+1]=mp[i][q[head]];
        }
    }
    for(int i=1;i<=b;i++)
    {
        head=1,tail=0;
        for(int j=1;j<=a;j++)
        {
            while(head<=tail&&j-q[head]>=n)head++;
            while(head<=tail&&f[q[tail]][i]>=f[j][i])tail--;
            q[++tail]=j;
            if(j>=n)f_min[j-n+1][i]=f[q[head]][i];
        }
    }
    for(int i=1;i<=a;i++)
    {
        head=1,tail=0;
        for(int j=1;j<=b;j++)
        {
            while(head<=tail&&j-q[head]>=n)head++;
            while(head<=tail&&mp[i][q[tail]]<=mp[i][j])tail--;
            q[++tail]=j;
            if(j>=n)f[i][j-n+1]=mp[i][q[head]];
        }
    }
    for(int i=1;i<=b;i++)
    {
        head=1,tail=0;
        for(int j=1;j<=a;j++)
        {
            while(head<=tail&&j-q[head]>=n)head++;
            while(head<=tail&&f[q[tail]][i]<=f[j][i])tail--;
            q[++tail]=j;
            if(j>=n)f_max[j-n+1][i]=f[q[head]][i];
        }
    }
    int ans=0x7fffffff;
    for(int i=1;i<=a-n+1;i++)
        for(int j=1;j<=b-n+1;j++)
            ans=min(ans,f_max[i][j]-f_min[i][j]);
    printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/fangbozhen/p/11852068.html