概述
https://acm.sjtu.edu.cn/OnlineJudge/problem/1074
雪地只有脚印和空白两种状态,可以分别用1和0代表。而查询某一块区域是否可行,就是查询这块区域内所有点的和是否为0,自然用二维前缀和比较合适。
设某一块矩形左上角的坐标为
(i,j)
(
i
,
j
)
,短边长为
k
k
,对进行枚举,即可得到暴力做法,时间复杂度
O(n3)
O
(
n
3
)
。
//s是前缀和数组
int ans = 0;
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= n; ++j){
int maxlen = min(n - i + 1, (m - j + 1) / 2); // 当前位置的最大可能边长
for (int l = 1; l <= maxlen; ++l){
int x = i + l - 1, y = j + 2 * l - 1; // 右下角坐标
if (s[x][y] - s[i - 1][y] - s[x][j - 1] + s[i - 1][j - 1] == 0){
ans = max(ans, (x - i + 1) * (y - j + 1));
}
}
}
}
但是,这样只能通过
40%
40
%
的数据。
再考虑一下,能否缩小枚举的边长范围。可以发现,若用
f[i,j]
f
[
i
,
j
]
表示右下角在
(i,j)
(
i
,
j
)
的最大可行区域的边长,
f[i,j]
f
[
i
,
j
]
不会超过
f[i−1,j]+1
f
[
i
−
1
,
j
]
+
1
。
如图,红色部分为右下角在点A的最大可行区域,现在考虑右下角在点B的最大可行区域。若其边长比A大2(黄色部分),则黑框范围同样是右下角在点A的可行区域,矛盾。因此,区域B的边长最多比A大1(橙色部分)。利用这个性质,当整张图中脚印分布较为均匀时,可以大大缩小边长的枚举范围。
//a是原数组,s是前缀和,f如上所述
for (int i = 1; i <= n; ++i){
for (int j = 2; j <= m; ++j){
if (a[i][j])
continue; //此处本身有脚印,不存在可行区域
for (int t = f[i - 1][j] + 1; t >= 1; --t){ //枚举边长
int x = i - t + 1, y = j - 2 * t + 1; //左上角坐标
if (x <= 0 || y <= 0)
continue;
int p = s[i][j] - s[x - 1][j] - s[i][y - 1] + s[x - 1][y - 1];
if (p == 0){
f[i][j] = t;
break; //已经找到了一个解,就无须再考虑边长更小的解了
}
}
}
}
最后
以上就是感动白开水为你收集整理的【SJTUOJ笔记】P1074 LSZ的雪地脚印的全部内容,希望文章能够帮你解决【SJTUOJ笔记】P1074 LSZ的雪地脚印所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复