題目鏈接:https://codeforces.com/contest/1301/problem/E
題目大意:
左上角紅,右上角綠,左下角黃,右下角藍的正方形被算作合格的logo,給一張圖和一個範圍,問範圍內最大的合格logo有多大
題目思路:
三步走,第一步,求各種顏色數量的二維前綴和。
第二步,假設每一個點作爲紅色的右下角,能形成多大的logo,通過二分實現,check的條件就是左上右上左下右下都是指定的顏色, 就是規定範圍內的顏色數量正好是規定範圍大小。
第三步,對第二步得到的大小進行ST表預處理,然後二分每種顏色的邊長,由於之前處理的是針對紅色的,所以這裏也是。爲了防止這傢伙越過三八線,所以這裏有個很巧妙地操作,就是一定要在合法區域內選擇紅色區域的右下角,他必須距離左邊和上邊mid-1,但是距離右邊和底邊是mid,因爲那塊區域是別的顏色負責的,要是這個範圍內能找到值大於等於mid的,那都是沒毛病的,都可以在選定範圍內出現。
以下是代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 505+5;
const int MOD = 1e9+7;
char s[MAXN][MAXN];
int n,m,q,sum[MAXN][MAXN][4],a[MAXN][MAXN];
int f[10][10][MAXN][MAXN],lg[MAXN];
void Build_2D_Sparse_Table(int n, int m){
int i, j, k1, k2;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[0][0][i][j]=a[i][j];
}
}
for(i = 2; i < MAXN ; i++)
lg[i] = 1 + lg[i/2];
for(i = 1; i <= n; i++)
for(k2 = 1; (1 << k2) <= m; k2++)
for(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(k1 = 1; (1 << k1) <= n; k1++)
for(i = 1; i <= n - (1 << k1) + 1; i++)
for(k2 = 0; (1 << k2) <= m; k2++)
for(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], k2 = lg[y2 - y1 + 1];
x2 = x2 - (1 << k1) + 1;
y2 = y2 - (1 << k2) + 1;
return max(max(f[k1][k2][x1][y1],f[k1][k2][x1][y2]),max(f[k1][k2][x2][y1],f[k1][k2][x2][y2]));
}
int getsum(int x1,int y1,int x2,int y2,int c){
if(x1<1||x1>n)return 0;
if(x2<1||x2>n)return 0;
if(y1<1||y1>m)return 0;
if(y2<1||y2>m)return 0;
return sum[x2][y2][c]-sum[x1-1][y2][c]-sum[x2][y1-1][c]+sum[x1-1][y1-1][c];
}
bool check(int x,int y,int val){
if(getsum(x-val+1,y-val+1,x,y,0)<val*val)return false;
if(getsum(x-val+1,y+1,x,y+val,1)<val*val)return false;
if(getsum(x+1,y-val+1,x+val,y,2)<val*val)return false;
if(getsum(x+1,y+1,x+val,y+val,3)<val*val)return false;
return true;
}
int check2(int r1,int c1,int r2,int c2,int mid){
if(r1>r2||c1>c2)return false;
return Query(r1,c1,r2,c2)>=mid;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&q)){
rep(i,1,n){
scanf("%s",s[i]+1);
}
memset(sum,0,sizeof(sum));
rep(i,1,n){
rep(j,1,m){
rep(k,0,3){
sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
}
if(s[i][j]=='R')sum[i][j][0]++;
if(s[i][j]=='G')sum[i][j][1]++;
if(s[i][j]=='Y')sum[i][j][2]++;
if(s[i][j]=='B')sum[i][j][3]++;
}
}
rep(i,1,n){
rep(j,1,m){
int l=0,r=min(n,m),ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(i,j,mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
a[i][j]=ans;
}
}
Build_2D_Sparse_Table(n,m);
while(q--){
int r1,c1,r2,c2;
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
int l=0,r=min(n,m),ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check2(r1+mid-1,c1+mid-1,r2-mid,c2-mid,mid)){
l=mid+1;
ans=4*mid*mid;
}
else r=mid-1;
}
printf("%d\n",ans);
}
}
return 0;
}