题目链接: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;
}