zzzyc

导航

[HAOI2007]理想的正方形

单调队列维护区间最大值最小值。。。

用 X[ i ][ j ] 表示 第 i 行 从第 j 列到第 j+n-1 列 的最大值。。。

反之,用 x[ i ][ j ] 表示最小值。。。

接下来用同种方法。。。利用 X 和 x 对每一列进行维护。。。记作 Y[ i ][ j ] y[ i ][ j ]

最后。。。枚举 i j 取最小的 Y[ i ][ j ] - y[ i ][ j ] 就是答案。。。

呆码:

#include<iostream>
#include<cstdio>
using namespace std;

int a,b,n,head1,head2,tail1,tail2,ans=999999999;
int c[1010][1010],q1[1010],q2[1010];
int X[1010][1010],x[1010][1010],Y[1010][1010],y[1010][1010];

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",&c[i][j]);

    for(int i=1;i<=a;i++)
    {
        head1=head2=tail1=tail2=q1[1]=q2[1]=1;
        for(int j=2;j<=b;j++)
        {
            while(head1<=tail1 && c[i][j]>=c[i][q1[tail1]]) tail1--;
            while(head2<=tail2 && c[i][j]<=c[i][q2[tail2]]) tail2--;
            q1[++tail1]=j; q2[++tail2]=j;
            while(j-q1[head1]>=n) head1++;
            while(j-q2[head2]>=n) head2++;
            if(j>=n) X[i][j-n+1]=c[i][q1[head1]];
            if(j>=n) x[i][j-n+1]=c[i][q2[head2]];
        }
    }

    for(int i=1;i<=b-n+1;i++)
    {
        head1=head2=tail1=tail2=q1[1]=q2[1]=1;
        for(int j=2;j<=a;j++)
        {
            while(head1<=tail1 && X[j][i]>=X[q1[tail1]][i]) tail1--;
            while(head2<=tail2 && x[j][i]<=x[q2[tail2]][i]) tail2--;
            q1[++tail1]=j; q2[++tail2]=j;
            while(j-q1[head1]>=n) head1++;
            while(j-q2[head2]>=n) head2++;
            if(j>=n) Y[j-n+1][i]=X[q1[head1]][i];
            if(j>=n) y[j-n+1][i]=x[q2[head2]][i];
        }
    }

    for(int i=1;i<=a-n+1;i++)
        for(int j=1;j<=b-n+1;j++)
            ans=min(ans,Y[i][j]-y[i][j]);
    printf("%d\n",ans);
}
代码

 

posted on 2018-07-13 09:28  zzzyc  阅读(107)  评论(0编辑  收藏  举报