1 条题解
-
0
题目详解
问题重述
我们有一个 的网格,需要放置 只大猩猩(每只大猩猩有身高 ,每个格子最多放一只)。定义观赏值为:所有边长为 的子正方形的观赏值之和,其中每个子正方形的观赏值等于其中所有大猩猩身高之和。
我们需要最大化这个总观赏值。
核心思路
1. 每个格子对总观赏值的贡献次数
关键观察:
对于网格中的某个格子 (这里 从 开始索引),它会被多少个边长为 的子正方形覆盖?推导方法
一个边长为 的子正方形由其左上角 唯一确定,其中:
格子 被该子正方形覆盖,当且仅当:
同时 必须满足 , 必须满足 。
因此 的取值范围是:
$$x_{\min} = \max(0, i - k + 1), \quad x_{\max} = \min(i, n - k) $$的取值范围是:
$$y_{\min} = \max(0, j - k + 1), \quad y_{\max} = \min(j, m - k) $$所以格子 被覆盖的次数为:
$$cnt(i, j) = (\min(i, n - k) - \max(-1, i - k)) \times (\min(j, m - k) - \max(-1, j - k)) $$注意:代码中使用
$$cnt(i, j) = (\min(i, n - k) - \max(0, i - k + 1) + 1) \times (\min(j, m - k) - \max(0, j - k + 1) + 1) $$max(-1LL, i - k)是因为当 时,,相减后得到 ,等价于 。实际上更清晰的写法是:但原代码的写法在数学上是等价的。
2. 贪心策略
总观赏值可以写成:
$$\text{总观赏值} = \sum_{\text{每个子正方形}} \sum_{\text{格子在子正方形中}} a_{格子} = \sum_{\text{每个格子}} cnt(i, j) \times a_{格子} $$也就是说,每个格子的“重要性”就是它被覆盖的次数 。
为了最大化总和,我们应该:
- 将最大的 分配给最大的 (身高)
- 将第二大的 分配给第二大的
- 以此类推
这就是一个典型的贪心策略:大的乘大的,小的乘小的。
3. 算法步骤
- 计算每个格子的覆盖次数 ,存入数组
prr。 - 对大猩猩身高数组
arr从大到小排序。 - 对覆盖次数数组
prr从大到小排序。 - 计算 (注意只有前 个格子被放置大猩猩,因为 ,未被使用的格子贡献为 )。
时间复杂度分析
- 计算所有 个格子的覆盖次数:
- 排序
arr: - 排序
prr: - 总复杂度:
由于所有测试用例的 之和不超过 , 之和也不超过 ,因此可以在时限内运行。
代码对应关系
函数/变量 作用 calcc(i, j)计算格子 被覆盖的次数 build()1. 将 arr降序排序
2. 遍历所有格子,计算覆盖次数存入prr
3. 将prr降序排序solve()计算
示例验证(第一个测试用例)
所有 ,所以任何安排结果相同。先计算覆盖次数矩阵():
手动计算几个:
- 角上格子 :能被左上角在 的 子正方形覆盖,只有 个 →
- 边中格子 :能被左上角在 和 的两个子正方形覆盖 →
- 中心格子 :能被左上角在 的 个子正方形覆盖 →
覆盖次数矩阵:
1 2 2 1 2 4 4 2 1 2 2 1总观赏值 = ? 不对,需要乘以身高(都是 )。
实际上,总观赏值 = 所有覆盖次数之和 = ?但答案是 。
这里需要小心:我们只有 只大猩猩,不是 个格子。
所以我们要取覆盖次数最大的 个格子:?
排序后:
和 = ✅
注意事项
- 使用
long long存储结果,因为身高最大 ,覆盖次数最大约 (但 ),乘积可能很大。 - 覆盖次数计算时,注意边界条件,尤其是 或 的情况。
- 如果 ,只使用覆盖次数最大的 个格子,其余格子不放大猩猩。
- 1
信息
- ID
- 6303
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者