zoukankan      html  css  js  c++  java
  • 一本通1604理想的正方形

    1604:理想的正方形

    时间限制: 1000 ms         内存限制: 524288 KB

    【题目描述】

    原题来自:HAOI 2007

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

    【输入】

    第一行为三个整数,分别表示 a,b,n 的值;

    第二行至第 a+1 行每行为 b 个非负整数,表示矩阵中相应位置上的数。

    【输出】

    输出仅一个整数,为 a×b 矩阵中所有「n×n 正方形区域中的最大整数和最小整数的差值」的最小值。

    【输入样例】

    5 4 2
    1 2 5 6
    0 17 16 0
    16 17 2 1
    2 10 2 1
    1 2 2 2

    【输出样例】

    1

    【提示】

    数据范围与提示:

    对于 20% 的数据 2a,b100,n10

    对于 100% 的数据 2a,b1000,na,nb,n100,矩阵中的所有数都不超过 109

    sol:这题有两种做法(二维ST表,二维单调队列)

    二维ST表:顾名思义二维的ST表,ST[i][j][k]表示以(i,j)为左下角,边长为 2的正方形的最值,很好处理

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-');
            ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');
            return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    inline void writeln(ll x)
    {
        write(x);
        putchar('
    ');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) writeln(x)
    const int N=1005,B=10,inf=0x3f3f3f3f;
    int n,m,K,St_Max[N][N][B],St_Min[N][N][B];
    inline int Max4(int a,int b,int c,int d)
    {
        int e=max(a,b),f=max(c,d); return max(e,f);
    }
    inline int Min4(int a,int b,int c,int d)
    {
        int e=min(a,b),f=min(c,d); return min(e,f);
    }
    int main()
    {
    //    freopen("square1.in","r",stdin);
        int i,j,k;
        R(n); R(m); R(K);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++) St_Max[i][j][0]=St_Min[i][j][0]=read();
        }
        for(i=1;i<=7;i++)
        {
            for(j=1;j+(1<<i)-1<=n;j++)
            {
                for(k=1;k+(1<<i)-1<=m;k++)
                {
                    St_Max[j][k][i]=Max4(St_Max[j][k][i-1],St_Max[j+(1<<(i-1))][k][i-1],St_Max[j][k+(1<<(i-1))][i-1],St_Max[j+(1<<(i-1))][k+(1<<(i-1))][i-1]);
                    St_Min[j][k][i]=Min4(St_Min[j][k][i-1],St_Min[j+(1<<(i-1))][k][i-1],St_Min[j][k+(1<<(i-1))][i-1],St_Min[j+(1<<(i-1))][k+(1<<(i-1))][i-1]);
                }
            }
        }
        int ans=inf;
        int oo;
        for(oo=0;;oo++) if(((1<<oo)<=K)&&((1<<(oo+1))>=K)) break;
        for(i=1;i+K-1<=n&&ans;i++)
        {
            for(j=1;j+K-1<=m&&ans;j++)
            {
                int o1=Max4(St_Max[i][j][oo],St_Max[i+K-1-(1<<oo)+1][j][oo],St_Max[i][j+K-1-(1<<oo)+1][oo],St_Max[i+K-1-(1<<oo)+1][j+K-1-(1<<oo)+1][oo]);
                int o2=Min4(St_Min[i][j][oo],St_Min[i+K-1-(1<<oo)+1][j][oo],St_Min[i][j+K-1-(1<<oo)+1][oo],St_Min[i+K-1-(1<<oo)+1][j+K-1-(1<<oo)+1][oo]);
                ans=min(ans,o1-o2);
            }
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    5 4 2
    1 2 5 6
    0 17 16 0
    16 17 2 1
    2 10 2 1
    1 2 2 2
    output
    1
    */
    二维ST表

    二维单调队列:先处理出Min[i][j][0]表示以(i,j)为右下角的长度为n的一整条中的最小值,用单调队列a*b就可以处理出来了

    再用Min[i][j][0]到列上去跑单调队列,得到Min[i][j][1]表示以(i,j)为右下角的一个n*n的正方形中的最小值

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-');
            ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');
            return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    inline void writeln(ll x)
    {
        write(x);
        putchar('
    ');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) writeln(x)
    const int N=1005,inf=0x3f3f3f3f;
    int n,m,L,Val[N][N];
    int Min[N][N][2],Max[N][N][2];
    struct Record
    {
        int Shuz,Weiz;
    }Ddq[N];
    int main()
    {
    //    freopen("square1.in","r",stdin);
        int i,j,Head,Tail;
        R(n); R(m); R(L);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++) R(Val[i][j]);
        }
        for(i=1;i<=n;i++)
        {
            Head=1; Tail=0;
            for(j=1;j<=m;j++)
            {
                while(Head<=Tail&&Val[i][j]<Ddq[Tail].Shuz) Tail--;
                Ddq[++Tail]=(Record){Val[i][j],j};
                while(Head<Tail&&Ddq[Head].Weiz<j-L+1) Head++;
                Min[i][j][0]=Ddq[Head].Shuz;
            }
            Head=1; Tail=0;
            for(j=1;j<=m;j++)
            {
                while(Head<=Tail&&Val[i][j]>Ddq[Tail].Shuz) Tail--;
                Ddq[++Tail]=(Record){Val[i][j],j};
                while(Head<Tail&&Ddq[Head].Weiz<j-L+1) Head++;
                Max[i][j][0]=Ddq[Head].Shuz;
            }
        }
        for(j=L;j<=m;j++)
        {
            Head=1; Tail=0;
            for(i=1;i<=n;i++)
            {
                while(Head<=Tail&&Min[i][j][0]<Ddq[Tail].Shuz) Tail--;
                Ddq[++Tail]=(Record){Min[i][j][0],i};
                while(Head<Tail&&Ddq[Head].Weiz<i-L+1) Head++;
                Min[i][j][1]=Ddq[Head].Shuz;
            }
            Head=1; Tail=0;
            for(i=1;i<=n;i++)
            {
                while(Head<=Tail&&Max[i][j][0]>Ddq[Tail].Shuz) Tail--;
                Ddq[++Tail]=(Record){Max[i][j][0],i};
                while(Head<Tail&&Ddq[Head].Weiz<i-L+1) Head++;
                Max[i][j][1]=Ddq[Head].Shuz;
            }
        }
        int ans=inf;
        for(i=L;i<=n;i++)
        {
            for(j=L;j<=m;j++) ans=min(ans,Max[i][j][1]-Min[i][j][1]);
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    5 4 2
    1 2 5 6
    0 17 16 0
    16 17 2 1
    2 10 2 1
    1 2 2 2
    output
    1
    */
    二维单调队列
  • 相关阅读:
    XPath使用
    正则表达式使用步骤
    os模块
    每天记十个单词
    Ubuntu下MySQL服务器,客户端安装
    使用Python3将代码打包成exe程序并添加图标的方法
    使用Python自动刷王者荣耀金币
    Ubuntu 18.04TLS命令安装谷歌浏览器
    Ubuntu 18.04TLS命令安装Python3.8
    Ubuntu 18.04TLS命令安装搜狗输入法
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10380889.html
Copyright © 2011-2022 走看看