题解- C F 1301 E N a n o s o f t CF1301E \ Nanosoft CF1301E Nanosoft
-
题目意思
就是让你在一个区域中找到最大符合条件的正方形。
-
S o l Sol Sol
考虑暴力用前缀和优化来统计答案。
首先对于每一种颜色做一遍二位前缀和。然后 O ( n × m × min ( n , m ) ) O(n \times m \times \min(n,m)) O(n×m×min(n,m))暴力拓展处理出所有边长为 k k k的符合条件的正方形(具体做法看代码)。然后对一个符合条件的正方形的左上角打标记,再对整个矩形中符合条件的位置数做前缀和即可。然后就是 O ( Q × min ( n , m ) ) O(Q\times \min(n,m)) O(Q×min(n,m))查询即可。代码里有比较清楚的解释。
-
C o d e Code Code
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=505;
const int M=275;
char ch[N][N];
int n,m,Q,f[N][N],g[N][N][5],h[N][N][M],ans;
int main()
{
n=read();
m=read();
Q=read();
for ( int i=1;i<=n;i++ ) scanf("%s",ch[i]+1);
for ( int i=1;i<=n;i++ )
for ( int j=1;j<=m;j++ )
{
for ( int k=0;k<4;k++ )
g[i][j][k]=g[i-1][j][k]+g[i][j-1][k]-g[i-1][j-1][k];
if(ch[i][j]=='R') g[i][j][0]++;
if(ch[i][j]=='G') g[i][j][1]++;
if(ch[i][j]=='B') g[i][j][2]++;
if(ch[i][j]=='Y') g[i][j][3]++;
}
//对每种颜色处理前缀和
for ( int i=1;i<n;i++ )
for ( int j=1;j<m;j++ )
if(ch[i][j]=='R'&&ch[i+1][j]=='Y'&&ch[i][j+1]=='G'&&ch[i+1][j+1]=='B')
{
f[i][j]=1;
for ( int k=2;k<=min(n,m)/2;k++ )
{
int x=i-k+1,y=j-k+1;
int a=i,b=j;
if(x<1||y<1) break;
//注意边界
if(g[a][b][0]-g[a][y-1][0]-g[x-1][b][0]+g[x-1][y-1][0]!=k*k) break;
x=i-k+1,y=j+1;
a=i,b=j+k;
if(x<1||y<1||a>n||b>m) break;
if(g[a][b][1]-g[a][y-1][1]-g[x-1][b][1]+g[x-1][y-1][1]!=k*k) break;
x=i+1,y=j+1;
a=i+k,b=j+k;
if(x<1||y<1||a>n||b>m) break;
if(g[a][b][2]-g[a][y-1][2]-g[x-1][b][2]+g[x-1][y-1][2]!=k*k) break;
x=i+1,y=j-k+1;
a=i+k,b=j;
//x,y,a,b表示每一块颜色的左上左下,右上右下的位置
if(x<1||y<1||a>n||b>m) break;
if(g[a][b][3]-g[a][y-1][3]-g[x-1][b][3]+g[x-1][y-1][3]!=k*k) break;
f[i-k+1][j-k+1]=k;
//对左上角打标记
}
}
for ( int i=1;i<n;i++ )
for ( int j=1;j<m;j++ )
if(f[i][j]) h[i][j][f[i][j]]=1;
//这个点对于边长k合法的
for ( int i=1;i<=n;i++ )
for ( int j=1;j<=m;j++ )
for ( int k=1;k<=min(n,m)/2;k++ )
h[i][j][k]+=h[i-1][j][k]+h[i][j-1][k]-h[i-1][j-1][k];//对合法点数量做前缀和
while(Q--)
{
int x=read(),y=read();
int xx=read(),yy=read();
int mx=min(xx-x+1,yy-y+1)/2;
for ( int k=mx;k>=1;k-- )//打着枚举,找到就结束
{
int sx=xx-2*k+1;
int sy=yy-2*k+1;
if(h[sx][sy][k]-h[sx][y-1][k]-h[x-1][sy][k]+h[x-1][y-1][k])
{
printf("%d\n",k*k*4);
goto sleep;
}
}
printf("0\n");
sleep:;
}
return 0;
}