codeforces - 1301E - Nanosoft(预处理+二位前缀和+思维)
题目大意:
题目思路:
先将这个题目简化一下:
假设我们每次查询,固定矩阵大小,即不考虑子矩阵
那么我们可以从左上角的端点每次让半径逐渐扩展,check后得到答案
这里check的时候只需要预处理出四种颜色的二位前缀然后再进行区间的计算就ok了
但是如果要考虑子矩阵呢
如果枚举矩阵的每个点作为左上角,然后扩展,这样复杂度是O(Q*N^3)
优化1:
如果对于每个左上角,我们知道他的最长合法半径,可以将复杂度优化到O(Q*N^2)
显然还是不太理想
优化2:
我们用数组c[ i ] [ j ] [ k ]
记录i,j作为左上角时候, 半径为k的时候是否可以构成logo
我们对c数组求一个前缀和
这样每次查询一个半径是否合法的时候就可以在O(1)得出答案
时间复杂度:O(Q*N)
具体操作:
step1:对四种颜色求前缀和
step2:枚举i,j作为左上角的点,寻找最大合法半径
step3: 对c数组求前缀和
step4:对于每次询问,从大到小枚举半径,check是否合法
如何check:
假设询问的区间左上角是x1,y1右下角是x2,y3,此时枚举到半径为k时
更新右下角为x3 = x2 - 2k +1 , y3 = y2 - 2k+1;
因为删除掉的部分,有些点在半径为k时是合法的,所以会产生共贡献
CODE:
// Problem: E. Nanosoft
// Contest: Codeforces - Codeforces Round #619 (Div. 2)
// URL: https://codeforces.com/contest/1301/problem/E
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 7;
const ll mod = 1e9 + 7;
#define pb push_back
#define debug(x) cout << #x << ":" << x << endl;
#define mst(x, a) memset(x, a, sizeof(x))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define dep(i, a, b) for (int i = (a); i >= (b); --i)
inline ll read() {
ll x = 0;
bool f = 0;
char ch = getchar();
while (ch < '0' || '9' < ch)
f |= ch == '-', ch = getchar();
while ('0' <= ch && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return f ? -x : x;
}
void out(ll x) {
int stackk[20];
if (x < 0) {
putchar('-');
x = -x;
}
if (!x) {
putchar('0');
return;
}
int top = 0;
while (x)
stackk[++top] = x % 10, x /= 10;
while (top)
putchar(stackk[top--] + '0');
}
ll qpow(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int n, m, qq;
char s[666];
int sum[502][502][5];
int f[502][502];
int get(int x1, int y1, int x2, int y2, int z) {
return sum[x2][y2][z] - sum[x2][y1 - 1][z] - sum[x1 - 1][y2][z] + sum[x1 - 1][y1 - 1][z];
}
int check(int x1, int y1, int x2, int y2) {
if (x1 < 1 || x1 > n || x2 < 1 || x2 > n)
return 1;
if (y1 < 1 || y2 < 1 || y2 > m || y1 > m)
return 1;
return 0;
}
int num[502][502][253],c[502][502][253];
int main() {
// ios::sync_with_stdio(false);
n = read(), m = read(), qq = read();
// RGYB
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
for (int j = 1; j <= m; j++) {
sum[i][j][1] =
sum[i - 1][j][1] + sum[i][j - 1][1] - sum[i - 1][j - 1][1] + (s[j] == 'R');
sum[i][j][2] =
sum[i - 1][j][2] + sum[i][j - 1][2] - sum[i - 1][j - 1][2] + (s[j] == 'G');
sum[i][j][3] =
sum[i - 1][j][3] + sum[i][j - 1][3] - sum[i - 1][j - 1][3] + (s[j] == 'Y');
sum[i][j][4] =
sum[i - 1][j][4] + sum[i][j - 1][4] - sum[i - 1][j - 1][4] + (s[j] == 'B');
}
}
mst(f, -1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int k = max(n, m) / 2 + 1; k >= 0; k--) {
if (f[i][j] != -1)
break;
int x1, y1, x2, y2;
x1 = i, y1 = j;
x2 = i + k, y2 = j + k;
if (check(x1, y1, x2, y2) || get(x1, y1, x2, y2, 1) != (k + 1) * (k + 1))
continue;
x1 = i, y1 = j + k + 1;
x2 = i + k, y2 = j + k + 1 + k;
if (check(x1, y1, x2, y2) || get(x1, y1, x2, y2, 2) != (k + 1) * (k + 1))
continue;
x1 = i + k + 1, y1 = j;
x2 = i + k + 1 + k, y2 = j + k;
if (check(x1, y1, x2, y2) || get(x1, y1, x2, y2, 3) != (k + 1) * (k + 1))
continue;
x1 = i + k + 1, y1 = j + k + 1;
x2 = i + k + 1 + k, y2 = j + k + 1 + k;
if (check(x1, y1, x2, y2) || get(x1, y1, x2, y2, 4) != (k + 1) * (k + 1))
continue;
f[i][j] = k + 1;
}
}
}
rep(i, 1, n) rep(j, 1, m) if (f[i][j] == -1) f[i][j] = 0;
rep(i, 1, n) rep(j, 1, m) if(f[i][j]) num[i][j][f[i][j]] = 1;
rep(i,1,n) rep(j,1,m) rep(k,1,252) c[i][j][k] = c[i-1][j][k]+c[i][j-1][k] - c[i-1][j-1][k] + num[i][j][k];
while (qq--) {
int x1, y1, x2, y2;
x1 = read(), y1 = read(), x2 = read(), y2 = read();
int flag=1;
for(int k=max(n,m)/2+1; k>=1 ;k--)
{
if(x1+k>x2||y1+k>y2) continue;
int x3=x2-k*2+1,y3=y2-k*2+1;
if(x3<1||y3<1||x3<x1||y3<y1) continue;
if(c[x3][y3][k] - c[x1-1][y3][k] - c[x3][y1-1][k] + c[x1-1][y1-1][k])
{
out(k*k*4);
puts("");
flag=0;
break;
}
}
if(flag) puts("0");
}
return 0;
}
/*
*/