题意:
给你一个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;
}