Codeforces 1301 E Nanosoft —— 二分+前缀和,求二维区间是否存在

This way

题意:

给你一个n*m的矩阵,每个位置有四种颜色之一。现在每次给你一个矩形范围的区间,问你其中最大的能作为标志的正方形的大小是多少。
标志一定是这种组成方式:
在这里插入图片描述

题解:

这道题我们是要查询二维区间的最大值,而这个最大值不好维护,因为区间的限制,会导致最大值可能在区间旁边的时候,有一部分被裁掉,所以它就不一定是最大值。
那么我们此时可以二分红色正方形的边长,然后查看里面是否存在满足答案的标志,需要注意查询的区间是给你的区间再往里缩减mid范围。
怎么求区间内是否存在长度为l的标志,dp的话需要开4维很明显不可以,但是前缀和的话只需要三维即可。dp[i][j][k]表示到第i行,第j列,标志中红色区域的边长为k时,前缀和中有多少个满足条件的标志。
那么处理dp[i][j][k],我们需要先处理sum[i][j][k]:到第i行,第j列,颜色为k的点的前缀和的数量。然后我们枚举k去做dp就很方便了。

#include<bits/stdc++.h>
using namespace std;
const int N=5e2+5;
int sum[N][N][4],dp[N][N][N/2];
char s[N][N],mp[4]={'R','G','B','Y'};
int n,m,q;
bool check(int x,int y,int l){
    if(x-l+1<=0||y-l+1<=0||x+l>n||y+l>m)return 0;
    if(sum[x][y][0]-sum[x-l][y][0]-sum[x][y-l][0]+sum[x-l][y-l][0]!=l*l)
        return 0;
    if(sum[x][y+l][1]-sum[x][y][1]-sum[x-l][y+l][1]+sum[x-l][y][1]!=l*l)
        return 0;
    if(sum[x+l][y+l][2]-sum[x+l][y][2]-sum[x][y+l][2]+sum[x][y][2]!=l*l)
        return 0;
    if(sum[x+l][y][3]-sum[x][y][3]-sum[x+l][y-l][3]+sum[x][y-l][3]!=l*l)
        return 0;
    return 1;
}
bool check(int x1,int y1,int x2,int y2,int l){
     return dp[x2][y2][l]-dp[x2][y1-1][l]-dp[x1-1][y2][l]+dp[x1-1][y1-1][l];
}
int main()
{

    scanf("%d%d%d",&n,&m,&q);
    int mx=min(n/2,m/2);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++)
            for(int k=0;k<4;k++)
                sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(s[i][j]==mp[k]);
    }
    int f=check(2,2,2);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=mx;k++)
                dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k]-dp[i-1][j-1][k]+check(i,j,k);
    while(q--){
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int l=1,r=min((x2-x1+1)/2,(y2-y1+1)/2),mid,ans=0;
        while(r>=l){
            mid=l+r>>1;
            if(check(x1+mid-1,y1+mid-1,x2-mid,y2-mid,mid))
                ans=mid,l=mid+1;
            else
                r=mid-1;
        }
        printf("%d\n",ans*ans*4);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值