CodeForces - 1301E Nanosoft 二分+二维前缀和

一、内容

Warawreh created a great company called Nanosoft. The only thing that Warawreh still has to do is to place a large picture containing its logo on top of the company's building.

The logo of Nanosoft can be described as four squares of the same size merged together into one large square. The top left square is colored with red, the top right square is colored with green, the bottom left square is colored with yellow and the bottom right square is colored with blue.

An Example of some correct logos:

Input

The first line of input contains three integers n, m and q (1≤n,m≤500,1≤q≤3⋅105)

 — the number of row, the number columns and the number of options.

For the next n
lines, every line will contain m characters. In the i-th line the j-th character will contain the color of the cell at the i-th row and j

-th column of the Adhami's picture. The color of every cell will be one of these: {'G','Y','R','B'}.

For the next q
lines, the input will contain four integers r1, c1, r2 and c2 (1≤r1≤r2≤n,1≤c1≤c2≤m). In that option, Adhami gave to Warawreh a sub-rectangle of the picture with the upper-left corner in the cell (r1,c1) and with the bottom-right corner in the cell (r2,c2)

Output

For every option print the maximum area of sub-square inside the given sub-rectangle, which can be a NanoSoft Logo. If there are no such sub-squares, print 0

Examples

Input

5 5 5
RRGGB
RRGGY
YYBBG
YYBBR
RBBRG
1 1 5 5
2 2 5 5
2 2 3 3
1 1 3 5
4 4 5 5

Output

16
4
4
4
0

二、思路

  • 首先sum[i][j][c]: 保存每个字母的二维前缀和。c的含义 0:R 1:G 2:Y 3:B
  • vis[i][j][k]: 代表以(i,j)为左上角坐标,每个小区域长度为k的矩形是否符合LOGO。 符合为1,不符合为0。求出来vis后对vis求二维前缀和。 这样查询某段区域是否合法就可以O(1)查询
  • 然后就可以二分枚举答案。
  • 在这里插入图片描述

三、代码

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 505;
char g[N][N];
int n, m, q, mx, c1, c2, r1, r2, sum[N][N][4], vis[N][N][255];
inline bool fail(int c, int x1, int y1, int k) {
	//左上角(x, y) 右下角(x + k - 1, y + k - 1)
	int x2 = x1 + k - 1, y2 = y1 + k - 1;
	if ((sum[x2][y2][c] - sum[x1 - 1][y2][c] - sum[x2][y1 - 1][c] + sum[x1 - 1][y1 - 1][c]) != k * k) return true; 
 	return false;
}
inline bool check(int x, int y, int k) {
	if (fail(0, x, y, k)) return false;
	if (fail(1, x, y + k, k)) return false;
	if (fail(2, x + k, y, k)) return false;
	if (fail(3, x + k, y + k, k)) return false;
	return true;	
}
void init() {
	for (int k = 1; k <= mx; k++) {
		for (int i = 1; i + k * 2 - 1 <= n; i++) {
			for (int j = 1; j + k * 2 - 1 <= m; j++) {
				if (check(i, j, k)) vis[i][j][k] = 1;
			}
		}
	}
	//对vis求一个前缀和 
	for (int k = 1; k <= mx; k++) {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				vis[i][j][k] += vis[i][j - 1][k] + vis[i - 1][j][k] - vis[i - 1][j - 1][k];
			}
		}
	}
} 
inline bool ok(int k, int x1, int y1, int x2, int y2) {
	if (x2 <= 0 || y2 <= 0 || x2 > n || y2 > m) return false;
	return vis[x2][y2][k] - vis[x1 - 1][y2][k] - vis[x2][y1 - 1][k] + vis[x1 - 1][y1 - 1][k];
}
int main() {
	scanf("%d%d%d", &n, &m, &q);
	mx = min(n / 2, m / 2); //最大的长度 
	for (int i = 1; i <= n; i++) {
		scanf("%s", g[i] + 1);
		for (int j = 1; j <= m; j++) {
			if (g[i][j] == 'R') sum[i][j][0] = 1;
			else if (g[i][j] == 'G') sum[i][j][1] = 1;
			else if (g[i][j] == 'Y') sum[i][j][2] = 1;
			else if (g[i][j] == 'B') sum[i][j][3] = 1;
			//求二维前缀和
			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]; 
		}
	} 
	init(); //预处理出vis数组 
	for (int i = 1; i <= q; i++) {
		scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
		int mx = min((r2 - r1 + 1) / 2, (c2 - c1 + 1) / 2); //最大的长度 
		int l = 0, r = mx;
		while (l < r) {
			int mid = (l + r + 1) >> 1;
			int r3 = r2 - 2*mid + 1, c3 = c2 - 2*mid + 1; //可行的区域 
			if (ok(mid, r1, c1, r3, c3)) l = mid; 
			else r = mid - 1;
		}
		printf("%d\n", 4 * r * r);
	}
	return 0;
} 
发布了456 篇原创文章 · 获赞 466 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104326758
今日推荐