zoukankan      html  css  js  c++  java
  • Codeforces Round #619 (Div. 2)E思维+二维RMQ

    题:https://codeforces.com/contest/1301/problem/E

    题意:给个n*m的图形,q个询问,每次询问问询问区间最大的合法logo的面积是多少

    分析:由于logo是由4个同色的小正方形组成的,所以我们先考虑一个数组val[i][j]表示[i][j]位置为‘R' , [i+1][j]位置为’Y‘,[i][j+1]位置为’G‘,[i+1][j+1]位置为’B'所能形成的最大图案边长是多少;

       因为这样就只要预处理‘R’正方形沿着左上能形成的最大正方形,“Y”沿着左下能形成的最大正方形,’G‘沿着右上能形成的最大正方形,”B“沿着右下能形成的最大正方形,然后对于位置[i][j]就取min这四者;

       对于询问,我们只要二分答案搜到最大符合条件的就行了,注意这里的二分的mid,假设询问[r1,c1,r2,c2],则搜索访问应该在[r1+mid-1,c1+mid-1,r2-mid,c2-mid]的范围内搜索才是合法的;

       因为我们在二分时要求满足条件的mid就行,所以这里对val进行倍增处理;

       合法性:因为小的合法图案一定在大的合法图案里面,所以对val取的图案也许是超过询问范围,但我们上面已经对询问范围进行如上缩减,所以是合法的

    #include<bits/stdc++.h>
    using namespace std;
    const int M=505;
    const int N=10;
    int ex[4][M][M];
    int n,m,q;
    int val[M][M],f[N][N][M][M],lg[M];
    char s[M][M];
    void RMQ(int n,int m){
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                f[0][0][i+1][j+1]=val[i][j];
        for(int i=2;i<M;i++)
            lg[i]=1+lg[i/2];
        for(int i=1;i<=n;i++)
            for(int k2=1;(1<<k2)<=m;k2++)
                for(int j=1;j<=m-(1<<k2)+1;j++)
                    f[0][k2][i][j]=max(f[0][k2-1][i][j],f[0][k2-1][i][j+(1<<(k2-1))]);
        for(int k1=1;(1<<k1)<=n;k1++)
            for(int i=1;i<=n-(1<<k1)+1;i++)
                for(int k2=0;(1<<k2)<=m;k2++)
                    for(int j=1;j<=m-(1<<k2)+1;j++)
                        f[k1][k2][i][j]=max(f[k1-1][k2][i][j],f[k1-1][k2][i+(1<<(k1-1))][j]);
    }
    
    
    int query(int x1,int y1,int x2,int y2){
        int k1=lg[x2-x1+1];
        int k2=lg[y2-y1+1];
        x2=x2-(1<<k1)+1;
        y2=y2-(1<<k2)+1;
        return max(f[k1][k2][x1][y1],max(f[k1][k2][x1][y2],max(f[k1][k2][x2][y1],f[k1][k2][x2][y2])));
    }
    bool check(int r1,int c1,int r2,int c2,int midd){
        r1=r1+midd-1;
        c1=c1+midd-1;
        r2=r2-midd;
        c2=c2-midd;
        if(r1>r2||c1>c2)
            return false;
        return query(r1,c1,r2,c2)>=midd;
    }
    void color(int fx,int fy,char c,int k){///根据进来的参数不同,组成不同方向相同颜色的最大正方形 
        int stx=0,sty=0;
        if(fx==-1)stx=n-1;
        if(fy==-1)sty=m-1;
        ///while遍历二维数组 
        while(stx<n&&stx>=0){
            while(sty<m&&sty>=0){
                if(s[stx][sty]==c){
                    ex[k][stx][sty]=1;
                    if(stx-fx>=0&&stx-fx<n&&sty-fy>=0&&sty-fy<m){///正方形区域取最小值 
                        if(s[stx-fx][sty]==c&&s[stx][sty-fy]==c&&s[stx-fx][sty-fy]==c){
                            ex[k][stx][sty]=min(ex[k][stx-fx][sty],
                                             min(ex[k][stx][sty-fy],ex[k][stx-fx][sty-fy]))+1;
                        }
                    }
                }
                sty+=fy;
            }
            sty=0;if(fy==-1)sty=m-1;
            stx+=fx;
        }
    }
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0;i<n;i++)
            scanf("%s",s[i]); 
        //1
        color(1,1,'R',0);
        color(-1,1,'Y',1);
        color(1,-1,'G',2);
        color(-1,-1,'B',3);
        for(int i=0;i<n-1;i++){
            for(int j=0;j<m-1;j++){
                if(s[i][j]=='R'&&s[i+1][j]=='Y'&&s[i][j+1]=='G'&&s[i+1][j+1]=='B'){
                    val[i][j]=min(ex[0][i][j],min(ex[1][i+1][j],min(ex[2][i][j+1],ex[3][i+1][j+1])));
                }
            }
        }
        //2
        RMQ(n,m);
    
        //3
        for(int i=0;i<q;i++){
            int r1,c1,r2,c2,ans=0;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            int l=0,r=min(r2-r1,c2-c1);
            while(l<=r){
                int midd=(l+r)>>1;
                if(check(r1,c1,r2,c2,midd)){
                    ans=midd;
                    l=midd+1;
                }
                else
                    r=midd-1;
            }
            printf("%d
    ",4*ans*ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Xshell 使用纪要
    矩阵求逆
    Ubuntu 增加新用户
    matlab 常用图像处理
    Surface Evolver 基本操作、使用指南和珍贵资料
    latex 裁剪图片
    Inkscape 输入希腊字母
    Pyton——int内部功能介绍
    python——登陆接口设计(循环方法)
    Python之三层菜单
  • 原文地址:https://www.cnblogs.com/starve/p/12348177.html
Copyright © 2011-2022 走看看