BZOJ 1047 【HAOI2007】 理想的正方形

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1047

【题意】

在a行b列的矩阵中找一个n*n的子矩阵,使得其最大值与最小值之差最小。

a,b≤1,000


【题解】

两次单调队列

先对每一行做单调队列,求出每个格子向左延伸n格之内的最小值b1和最大值b2

再对每一列做单调队列,利用之前求出的b1和b2,可得出以每个格子为右下角的n*n的矩阵的最小值minnum和最大值maxnum

再枚举每一个右下角,比较出最小值。


【代码】

#include <iostream>

#include <cstdio>

#include <cstdlib>

using namespace std;

 

int A,B,n;

int a[1010][1010],b1[1010][1010],b2[1010][1010],maxnum[1010][1010],minnum[1010][1010],st1[1010],st2[1010];

 

int main()

{

    int top1,top2,size1,size2,i,j;

    scanf("%d%d%d",&A,&B,&n);

    for (i=1;i<=A;i++)

        for (j=1;j<=B;j++)

            scanf("%d",&a[i][j]);

    for (i=1;i<=A;i++)

    {

        top1=top2=1,size1=size2=0;

        for (j=1;j<=B;j++)

        {

            if (a[i][j]>a[i][st1[size1]] || size1==0)

                st1[++size1]=j;

            else

            {

                while (a[i][j]<=a[i][st1[size1]] && size1>=top1)

                    size1--;

                st1[++size1]=j;

            }

            if (st1[top1]<=j-n) top1++;

            if (a[i][j]<a[i][st2[size2]] || size2==0)

                st2[++size2]=j;

            else

            {

                while (a[i][j]>=a[i][st2[size2]] && size2>=top2)

                    size2--;

                st2[++size2]=j;

            }

            if (st2[top2]<=j-n) top2++;

            if (j>=n)

            {

                b1[i][j]=a[i][st1[top1]];

                b2[i][j]=a[i][st2[top2]];

            }

        }   

    }

    for (j=n;j<=B;j++)

    {

        top1=top2=1,size1=size2=0;

        for (i=1;i<=A;i++)

        {

            if (b1[i][j]>b1[st1[size1]][j] || size1==0)

                st1[++size1]=i;

            else

            {

                while (b1[i][j]<=b1[st1[size1]][j] && size1>=top1)

                    size1--;

                st1[++size1]=i;

            }

            if (st1[top1]<=i-n) top1++;

            if (b2[i][j]<b2[st2[size2]][j] || size2==0)

                st2[++size2]=i;

            else

            {

                while (b2[i][j]>=b2[st2[size2]][j] && size2>=top2)

                    size2--;

                st2[++size2]=i;

            }

            if (st2[top2]<=i-n) top2++;

            if (i>=n)

            {

                minnum[i][j]=b1[st1[top1]][j];

                maxnum[i][j]=b2[st2[top2]][j];

            }

        }

    }

    int ans=2147483647;

    for (i=n;i<=A;i++)

        for (j=n;j<=B;j++)

            ans=min(ans,maxnum[i][j]-minnum[i][j]);

    printf("%d\n",ans);

    return 0;

}

评论

© CodeDevil | Powered by LOFTER