zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第三场)F Planting Trees 单调队列

    F Planting Trees

    题目链接

    https://ac.nowcoder.com/acm/contest/883/F

    题目描述

    The semester is finally over and the summer holiday is coming. However, as part of your university's graduation requirement, you have to take part in some social service during the holiday. Eventually, you decided to join a volunteer group which will plant trees in a mountain.
    To simplify the problem, let's represent the mountain where trees are to be planted with an (N imes N) grid. Let's number the rows ( 1) to ( N) from top to bottom, and number the columns ( 1) to ( N) from left to right. The elevation of the cell in the ( i)-th row and ( j)-th column is denoted by (a_{i,j}). Your leader decides that trees should be planted in a rectangular area within the mountain and that the maximum difference in elevation among the cells in that rectangle should not exceed M. In other words, if the coordinates of the top-left and the bottom-right corners of the rectangle are ((x_1,y_1)) and ((x_2,y_2)), then the condition $ |a_{i,j} - a_{k,l}| le M$ must hold for (x_1 le i,k le x_2, y_1 le j,l le y_2). Please help your leader calculate the maximum possible number of cells in such a rectangle so that he'll know how many trees will be planted.

    输入描述:

    The input contains multiple cases. The first line of the input contains a single integer (T (1 le T le 1000)), the number of cases.
    For each case, the first line of the input contains two integers $ N (1 le N le 500)$ and (M (0 le M le 10^5)). The following N lines each contain N integers, where the( j-th) integer in the i i i-th line denotes (a_{i,j} (1 le a_{i,j} le 10^5)).
    It is guaranteed that the sum of (N^3) over all cases does not exceed (25 cdot 10^7).

    输出描述:

    For each case, print a single integer, the maximum number of cells in a valid rectangle.

    输入

        2
        2 0
        1 2
        2 1
        3 1
        1 3 2
        2 3 1
        3 2 1
    

    输出

        1
        4
    

    题意

    给你一个(N imes N)的矩阵,求最大的自矩阵满足子矩阵中最大值和最小值只差小于m.

    题解

    一看体面最后一句话,寻思着就是(n^3)的算法,于是很自然地想到(n^2)枚举上届和下界,再用(n)来扫描一遍。

    我们想想假如上下界确定了,我们再枚举左边界,右边界越长越好,那么左边界往右移时,右边界一定不会往左移(这里应该不难想,只要想肯定不难想到),这个好像就叫做尺取法。

    剩下的就是要求区间的最小值和最大值了,我一开始直接二维倍增,结果超时了,改了两个小时还是超时,只能放弃了。之后用了单调队列来求最小值和最大值,这种做法感觉很经典,但是我竟然没看出来,还是做少了题目.

    简要地讲讲单调队列:

    我们搞两个队列,一个用来求最大值,另一个用来求最小值

    第一步:去掉不合法的队首(更改左边界)

    第二部:往后延伸右边界

    第三部:更新答案

    这么讲有点抽象,之后我去找找基础的题目,做完基础题目,这个自然也就会了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define INF 0x7f7f7f7f
    #define N 505
    #define maxx(a,b) a<b?b:a
    #define minn(a,b) a<b?a:b
    int n,m,mx[N],mi[N],a[N][N];
    struct Queue{int val,id;}Q1[N],Q2[N];
    clock_t now;
    template<typename T>void read(T&x)
    {
        ll k=0; char c=getchar();
        x=0;
        while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
        if (c==EOF)exit(0);
        while(isdigit(c))x=x*10+c-'0',c=getchar();
        x=k?-x:x;
    }
    inline void work()
    {
        now=clock();
        int ans=1;
        read(n); read(m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                read(a[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
            {
                int ds1=1,dw1=0,ds2=1,dw2=0,r=0;
                for(int k=1;k<=n;k++)
                {
                    if (i==j)mx[k]=mi[k]=a[i][k];
                    else {mx[k]=maxx(mx[k],a[j][k]);mi[k]=minn(mi[k],a[j][k]);}
                }
                for(int k=1;k<=n;k++)
                {
                    r=maxx(r,k-1);
                    while(ds1<=dw1&&Q1[ds1].id<k)ds1++;
                    while(ds2<=dw2&&Q2[ds2].id<k)ds2++;
                    if (mx[k]-mi[k]>m)continue;
                    int m1=maxx(mx[r+1],Q1[ds1].val);
                    int m2=minn(mi[r+1],Q2[ds2].val);
                    if (ds1>dw1)m1=mx[r+1],m2=mi[r+1];
                    while(r+1<=n&&(mx[r+1]-mi[r+1]<=m)&&(ds1>dw1||m1-m2<=m))
                        {
                            while(mx[r+1]>Q1[dw1].val&&ds1<=dw1)dw1--;
                            while(mi[r+1]<Q2[dw2].val&&ds2<=dw2)dw2--;
                            Q1[++dw1]={mx[r+1],r+1};
                            Q2[++dw2]={mi[r+1],r+1};
                            r++;
                            m1=maxx(m1,mx[r+1]);
                            m2=minn(m2,mi[r+1]);
                        }
                    ans=maxx(ans,(j-i+1)*(r-k+1));
                }
    
            }
        printf("%d
    ",ans);
        //cout<<(double)(clock()-now)/CLOCKS_PER_SEC*1000<<endl;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
        #endif
        int T;
        read(T);
        while(T--)work();
    }
    
    

    超时代码(仅供观赏)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define INF 0x7f7f7f7f
    #define N 505
    int n,m,mx[N][N][10][10],mi[N][N][10][10],mm[N],mv[10];
    template<typename T>void read(T&x)
    {
        ll k=0; char c=getchar();
        x=0;
        while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
        if (c==EOF)exit(0);
        while(isdigit(c))x=x*10+c-'0',c=getchar();
        x=k?-x:x;
    }
    void read_char(char &c)
    {while(!isalpha(c=getchar())&&c!=EOF);}
    void build_ST()
    {
        for(int i=2;i<=n;i++)mm[i]=mm[i>>1]+1;
        for(int i=0;i<=10;i++)mv[i]=1<<i;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                mx[i][j][0][0]=mi[i][j][0][0];
        for(int k=1;k<=8;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j+(1<<k)-1<=n;j++)
                {
                    mx[i][j][0][k]=max(mx[i][j][0][k-1],mx[i][j+(1<<(k-1))][0][k-1]);
                    mi[i][j][0][k]=min(mi[i][j][0][k-1],mi[i][j+(1<<(k-1))][0][k-1]);
                }
                          
        for(int k1=1;k1<=8;k1++)
            for(int k2=0;k2<=8;k2++)
                for(int i=1;i+(1<<k1)-1<=n;i++)
                    for(int j=1;j+(1<<k2)-1<=n;j++)
                    {
                        mx[i][j][k1][k2]=
                            max(mx[i][j][k1-1][k2],mx[i+(1<<(k1-1))][j][k1-1][k2]);
                        mi[i][j][k1][k2]=
                            min(mi[i][j][k1-1][k2],mi[i+(1<<(k1-1))][j][k1-1][k2]);
                    }
          
    }
    inline int get_mx(int x1,int y1,int x2,int y2)
    {
        int k1=mm[x2-x1+1],k2=mm[y2-y1+1];
        x2=x2-mv[k1]+1;
        y2=y2-mv[k2]+1;
        int a1=max(mx[x1][y1][k1][k2],mx[x1][y2][k1][k2]);
        int a2=max(mx[x2][y1][k1][k2],mx[x2][y2][k1][k2]);
        return max(a1,a2);
    }
    inline int get_mi(int x1,int y1,int x2,int y2)
    {
        int k1=mm[x2-x1+1],k2=mm[y2-y1+1];
        x2=x2-(1<<k1)+1;
        y2=y2-(1<<k2)+1;
        int a1=min(mi[x1][y1][k1][k2],mi[x1][y2][k1][k2]);
        int a2=min(mi[x2][y1][k1][k2],mi[x2][y2][k1][k2]);
        return min(a1,a2);
    }
    void work()
    {
        int ans=1;
        read(n); read(m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                read(mi[i][j][0][0]);
        build_ST();
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
            {
                int l=1;
                for(int k=1;k<=n;k++)
                {
                    int mx=get_mx(i,l,j,k);
                    int mi=get_mi(i,l,j,k);
                    while(mx-mi>m&&l<=k)
                    {
                        l++;
                        if(l<=k)mx=get_mx(i,l,j,k);
                        if(l<=k)mi=get_mi(i,l,j,k);
                    }
                    ans=max(ans,(j-i+1)*(k-l+1));
                }
            }
        printf("%d
    ",ans);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        int T;
        read(T);
        while(T--)work();
    }
    
  • 相关阅读:
    【笔记】 寻址方式
    今日思考之 20200614:java 中 null 是否对 gc 有帮助?
    分布式唯一ID生成方案对比分析 笔记
    请不要再称数据库是CP或者AP——CAP的误导(短板)和它的使命
    延迟初始化中的 双重检查模式 和 延迟占位类模式 你都用对了吗?
    redis bitmap
    RabbitMQ 使用 Policies HTTP API 绑定和解绑 DLX
    spring boot 自动装配的实现原理和骚操作,不同版本实现细节,debug 到裂开......
    netty 学习笔记三:大跃进,使用 netty 实现 IM 即时通讯系统
    一道 Java 方法传值面试题——Java方法传值的值传递概念和效果 + Integer 缓存机制 + 反射修改 private final 域
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11247624.html
Copyright © 2011-2022 走看看