题解:CF713D Animals and Puzzle
题意
给定一个
思路
首先考虑暴力,我们希望枚举询问矩形里的每个点,找到这一个点作为右下角的最大正方形(需要特判一下边界)。而每一个点对应的最大正方形边长也可以暴力预处理。时间复杂度
::::info[暴力代码] 暴力代码的预处理是把每个点作为右上角的。
#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void read(T &x){
T s = 0; int st = 1; char c = getchar();
while(c < '0' || c > '9'){(c == '-') && (st = -1); c = getchar();}
while(c >= '0' && c <= '9'){s = (s << 3) +(s << 1) + (c ^ 48); c = getchar();}
x = s * st;
}
template<typename T> inline void write(T x){
if(x <0) x= -x, putchar('-');
if(x > 9) write(x / 10);
putchar(x % 10 + 48);
}
#define LL long long
#define PII pair<int, int>
#define x1 orjsodfjdsofi
#define x2 dsoasgsapofj
#define y1 dlfzgjzdroier
#define y2 erogxlfigures
const int N = 1e3 + 5;
bool a[N][N];
int sum[N][N], sq[N][N];
inline int get1(int x1, int y1, int x2, int y2){
return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
}
int main(){
int n, m, q;
read(n), read(m);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
read(a[i][j]);
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
for(int i = 1; i <= m; ++i){
int l = 0, r = 0;
for(int j = 1; j <= n; ++j){
if(a[j][i]){
if(l == 0) l = r = j;
else r = j;
}
else l = r = 0;
int tmp = r - l + 1;
if(i + tmp - 1 > m) tmp = m - i + 1;
if(j - tmp + 1 < 0) tmp = j;
while(tmp > 0 && get1(j - tmp + 1, i, j, i + tmp - 1) < tmp * tmp){
--tmp;
}
sq[j][i] = tmp;
}
}
read(q);
while(q--){
int x1, x2, y1, y2, ans = 0;
read(x1), read(y1), read(x2), read(y2);
for(int i = x1; i <= x2; ++i){
for(int j = y1; j <= y2; ++j){
ans = max(ans, min({sq[i][j], i - x1 + 1, y2 - j + 1}));
}
}
write(ans);
putchar('\n');
}
return 0;
}
:::: 时间复杂度式子的每一项都需要优化。
预处理可以通过递推优化成
当
预处理部分优化完成,现在需要优化查询部分。
我们发现,对于一个合法边长
考虑二分答案的“check”函数。一个合法边长
问题转化成了求
一维 st 表是通过两个区间并求得的,二维 st 表就可以通过四个矩形并求。查询同理。
代码
注意 st 表部分容易出错,包括哪些地方有没有 -1 之类的,要仔细。
#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void read(T &x){
T s = 0; int st = 1; char c = getchar();
while(c < '0' || c > '9'){(c == '-') && (st = -1); c = getchar();}
while(c >= '0' && c <= '9'){s = (s << 3) +(s << 1) + (c ^ 48); c = getchar();}
x = s * st;
}
template<typename T> inline void write(T x){
if(x <0) x= -x, putchar('-');
if(x > 9) write(x / 10);
putchar(x % 10 + 48);
}
#define LL long long
#define PII pair<int, int>
#define x1 orjsodfjdsofi
#define x2 dsoasgsapofj
#define y1 dlfzgjzdroier
#define y2 erogxlfigures
const int N = 1e3 + 1;
int n, m, q;
int f[11][11][N][N], lg[N];
inline void init(){
for(int k = 1; k <= lg[n]; ++k){
for(int i = 1; i + (1 << k) - 1 <= n; ++i){
for(int j = 1; j <= m; ++j){
f[k][0][i][j] = max(f[k - 1][0][i][j], f[k - 1][0][i + (1 << k - 1)][j]);
}
}
}
for(int l = 1; l <= lg[m]; ++l){
for(int i = 1; i <= n; ++i){
for(int j = 1; j + (1 << l) - 1 <= m; ++j){
f[0][l][i][j] = max(f[0][l - 1][i][j], f[0][l - 1][i][j + (1 << l - 1)]);
}
}
}
for(int k = 1; k <= lg[n]; ++k){
for(int l = 1; l <= lg[m]; ++l){
for(int i = 1; i + (1 << k) - 1 <= n; ++i){
for(int j = 1; j + (1 << l) - 1 <= m; ++j){
f[k][l][i][j] = max({f[k - 1][l - 1][i][j],
f[k - 1][l - 1][i + (1 << k - 1)][j],
f[k - 1][l - 1][i][j + (1 << l - 1)],
f[k - 1][l - 1][i + (1 << k - 1)][j + (1 << l - 1)]});
}
}
}
}
}
inline int get(int x1, int y1, int x2, int y2){//左上角, 右下角
int lx = lg[x2 - x1 + 1], ly = lg[y2 - y1 + 1];
return max({f[lx][ly][x1][y1],
f[lx][ly][x1][y2 - (1 << ly) + 1],
f[lx][ly][x2 - (1 << lx) + 1][y1],
f[lx][ly][x2 - (1 <<lx) + 1][y2 - (1 << ly) + 1]});
}
int main(){
read(n), read(m);
for(int i = 2; i <= max(n, m); ++i) lg[i] = lg[i >> 1] + 1;
for(int i = 1, a; i <= n; ++i){
for(int j = 1; j <= m; ++j){
read(a);
if(a){
f[0][0][i][j] = min({f[0][0][i - 1][j], f[0][0][i][j - 1], f[0][0][i - 1][j - 1]}) + 1;
}
}
}
init();
read(q);
while(q--){
int x1, x2, y1, y2, l, r, mid, ans = 0;
read(x1), read(y1), read(x2), read(y2);
l = 1, r = min(y2 - y1 + 1, x2 - x1 + 1);
while(l <= r){
mid = l + r >> 1;
if(get(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid){
ans = mid;
l = mid + 1;
}
else{
r = mid - 1;
}
}
write(ans); putchar('\n');
}
return 0;
}
/*
3 4
1 1 0 1
0 1 1 0
0 1 1 0
5
1 1 2 3
2 1 3 2
3 2 3 4
1 1 3 4
1 2 3 4
*/
讲得有点抽象抱歉。这是今天学校 s 组%你赛 T3,赛时一直在想扫描线树套树之类的东西,最后只把暴力写了拿了 40 分非常遗憾,觉得题目还是有点价值于是克服倦意写了这篇题解。