zoukankan      html  css  js  c++  java
  • [BZOJ]1047 理想的正方形(HAOI2007)

      真·水题。小C本来是不想贴出来的,但是有一股来自东方的神秘力量催促小C发出来。

    Description

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

    Input

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

    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

    HINT

      2<=a,b<=1000,n<=a,n<=b,n<=1000

    Solution

      如果你是按照BZOJ第一页AC人数做下来的话,你的思路会被前一题稍微套路一下。

      回归正题,拿到这题我们正常的思路就是枚举所有矩阵,计算最大最小值更新答案。

      暴力O(n^4),二维线段树O(n^2logn)……发现可以降维(先做第一维,再做第二维)……发现询问区间长度固定……

      单调队列啊……

      每一行都维护两个单调队列(最大最小值),a行同时进行维护。

      维护到所有可能的右端点时,把维护的这a个最大/小值拿出来,在列上做一遍单调队列,顺便更新答案。

      时间复杂度O(n^2)。

      题解写得比较意识流,但小C认为如果你没懂不是小C的错。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define MN 1005
    #define INF 0x3FFFFFFF
    using namespace std;
    struct que
    {
        int hd,tl,q1[MN],q2[MN];
        void clear() {hd=1; tl=0;}
        int top() {return q2[hd];}
        void push(int x,int y,int g)
        {
            for (;hd<=tl&&((y>q2[tl])^g);--tl);
            ++tl; q1[tl]=x; q2[tl]=y;
        }
        void pop(int x) {for (;hd<=tl&&q1[hd]<=x;++hd);}
    }sdu[MN],sdd[MN],su,sd;
    int a[MN][MN];
    int n,m,p,ans;
    
    inline int read()
    {
        int n=0,f=1; char c=getchar();
        while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
        while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();}
        return n*f;
    }
    
    int main()
    {
        register int i,j;
        n=read(); m=read(); p=read(); ans=INF;
        for (i=1;i<=n;++i)
            for (j=1;j<=m;++j) a[i][j]=read();
        for (i=1;i<=n;++i) sdu[i].clear(),sdd[i].clear();
        for (i=1;i<=n;++i)
            for (j=1;j<p;++j) sdu[i].push(j,a[i][j],0),sdd[i].push(j,a[i][j],1);
        for (i=p;i<=m;++i)
        {
            su.clear(); sd.clear();
            for (j=1;j<=n;++j)
            {
                sdu[j].push(i,a[j][i],0); sdu[j].pop(i-p);
                sdd[j].push(i,a[j][i],1); sdd[j].pop(i-p);
                su.push(j,sdu[j].top(),0); su.pop(j-p);
                sd.push(j,sdd[j].top(),1); sd.pop(j-p);
                if (j>=p) ans=min(ans,su.top()-sd.top());
            }
        }
        printf("%d",ans);
    }

    Last Word

      小C才不会告诉你把这题贴出来的原因是小C觉得自己的代码好看。

  • 相关阅读:
    golang 带参数 发送、上传本地文件到其他机器、服务器
    【比赛游记】北大集训2020垫底记
    【比赛游记】NOIP2020又当工具人记
    AtCoder Regular Contest 107
    AtCoder Regular Contest 108
    【比赛游记】CSP2020游记
    注意事项
    2020北大集训摸鱼记
    NOIP2020游记
    ARC109F
  • 原文地址:https://www.cnblogs.com/ACMLCZH/p/7425605.html
Copyright © 2011-2022 走看看