題意:
給你一個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;
}