1 条题解
-
0
题目详解
问题理解
我们有一个 的网格,包含:
'.':空单元格(可以放置炸药)'g':金矿石'#':石头(无法放置炸药,但可能被爆炸影响)
炸药只能放在空单元格中。当在 引爆时,以 为中心、边长为 的正方形区域会被影响:
- 严格在正方形内部的金矿石会消失(损失)
- 在正方形边界上的金矿石会被收集
注意:爆炸可以超出网格边界,我们只关心网格内的金矿石。
关键观察
1. 多次爆炸可以收集所有剩余金矿石
考虑第一次爆炸后,位于爆炸正方形边界上的金矿石被收集,位于内部的金矿石消失。那么剩下的金矿石(未被第一次爆炸覆盖的)呢?
重要结论:我们可以通过后续的爆炸,收集所有剩余的金矿石。
方法:
- 第一次爆炸中心为 ,边长为
- 第二次爆炸:在所有位于第一次爆炸正方形边界的空单元格上引爆
- 这些爆炸的边长也是 ,它们会覆盖第一次爆炸正方形边界附近的区域
- 第三次爆炸:在第二次爆炸正方形的边界上引爆
- 依此类推,直到覆盖整个网格
通过这种方式,除了第一次爆炸内部的金矿石外,其他所有金矿石都能被收集。
2. 问题转化
因此,最大化收集的金矿石 最小化第一次爆炸损失的(即严格内部的)金矿石。
设:
- = 所有金矿石的总数
- = 第一次爆炸正方形内部的金矿石数(不包括边界)
- 则答案 =
我们需要选择最优的第一次爆炸位置(必须在空单元格),使得 最小。
算法步骤
步骤 1:计算金矿石总数
遍历整个网格,统计
'g'的个数,记为 。步骤 2:构建二维前缀和
为了快速计算任意矩形区域内金矿石的数量,我们构建二维前缀和数组 :
- 表示从 到 的矩形内金矿石的数量
- 公式:$sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + (grid[i-1][j-1] == 'g')$
步骤 3:枚举所有可能的第一次爆炸位置
对于每个空单元格 ():
- 爆炸正方形的边界范围:
- 上边界:
- 下边界:
- 左边界:
- 右边界:
- 爆炸正方形的内部(不包括边界):
- 行范围:
- 列范围:
- 但在代码中,为了简化,先计算整个正方形的金矿石数(包括边界),再考虑边界处理。
代码实现细节:
int a = i - k, b = i + k + 1; // b 是开区间右边界 int c = j - k, d = j + k + 1; // pref(b, d) - pref(a, d) - pref(b, c) + pref(a, c) // 计算的是 [a, b) × [c, d) 矩形内的金矿石数这里 和 可能为负数, 和 可能超过 ,但通过
check函数将坐标裁剪到 和 范围内。步骤 4:计算损失并更新答案
- 损失 = 第一次爆炸正方形内部的金矿石数
- 由于
pref(b, d) - pref(a, d) - pref(b, c) + pref(a, c)计算的是 内的金矿石数,这个区域正好是包含边界的正方形吗?
验证:
- 原始爆炸正方形边界:行从 到 ,列从 到
- 我们的区间:行 ,列
- 这正好是包含边界的整个正方形区域(包括边界上的格子)
但是题目要求:边界上的金矿石被收集,不算损失,只有严格内部的才算损失。
问题:代码直接用整个正方形的金矿石数作为损失,这正确吗?
仔细分析:
- 边界上的金矿石被收集,不应计入损失
- 严格内部的金矿石才会损失
- 但代码中并没有减去边界上的金矿石
重新审视:实际上,当 减少 1 时,边长为 的正方形变为边长为 的正方形,这正好是严格内部的区域。
代码中的处理:
k--; // 一开始就 k--然后在计算爆炸范围时:
int a = i - k, b = i + k + 1;此时的 已经减 1,所以实际计算的是边长为 的正方形?让我们检查:
设原始参数为 ,代码中
k--后 。 爆炸正方形边长 。而原始爆炸正方形的内部边长正好是 (因为外部边界宽度为 1)。
结论:代码通过
k--巧妙地直接计算了严格内部的金矿石数作为损失。步骤 5:输出答案
答案 =
复杂度分析
- 时间复杂度: 对于每个测试用例
- 计算前缀和:
- 枚举所有空单元格:
- 空间复杂度:
由于所有测试用例的 总和 ,完全可行。
示例验证
示例 1
2 3 1 #.# g.g(内部区域边长为 1) 总金矿石 枚举空单元格: 和 是石头, 是空 以 为中心,内部区域仅包含 本身(无金矿石) 答案
示例 2
2 3 2 #.# g.g,内部区域边长为 3 以 为中心,内部区域覆盖 到 ,包含所有 2 个金矿石 答案
示例 3
3 4 2 .gg. g..# g##.总金矿石 = 4 最优爆炸位置可以最小化损失,最终得到 4
核心思想总结
- 第一次爆炸的损失决定了最终能收集的金矿石数量
- 通过后续爆炸可以收集所有剩余金矿石
- 问题转化为:选择一个空单元格作为第一次爆炸中心,使得爆炸正方形内部的金矿石数最少
- 使用二维前缀和快速计算任意矩形内的金矿石数
- 通过 减 1 的技巧直接计算内部区域
- 1
信息
- ID
- 6558
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者