1 条题解
-
0
题解:D. Kousuke 的作业
问题重述
给定一个长度为 的数组 ,我们需要找到最多不重叠的子段,使得每个子段的元素和为 。
第一步:转化为前缀和问题
定义前缀和数组 :
那么对于子段 ,其元素和为:
子段和为 的条件等价于:
也就是说,一个子段是美丽的,当且仅当其左右端点对应的前缀和相等。
第二步:经典 DP 模型
这是一个典型的“最大不重叠区间”问题。
设 表示考虑前 个元素时,最多能选出的不重叠美丽子段数。
假设我们当前有一个美丽子段 ,那么:
其中:
- 表示不选当前子段;
- 表示选当前子段,并加上前面的最优解。
我们按子段的右端点 从小到大处理。
由于我们处理到 时,所有 的 都已经计算完毕,因此该 DP 是可行的。最终答案为 。
第三步:针对本题的优化
如果对于某个右端点 ,存在多个 使得 ,我们应该选哪一个?
我们只需要选 最大的 (即最靠右的左端点)对应的子段。
为什么?假设有两个左端点 都满足 。
那么子段 是 的子段。
如果选了较长的 ,那么内部必然包含更短的 ,这会导致无法再选取内部的子段,从而可能错过最优解。
而选择最短的子段 不会浪费内部可能存在的其他美丽子段。因此,对于每个 ,若存在 满足条件,我们只需要考虑最小的子段(即 最大的那个)。
第四步:算法实现
- 计算前缀和 ,。
- 使用哈希表(如
unordered_map)记录每个前缀和值最后一次出现的位置。 - 遍历 到 :
- 若 之前出现过,设其最后一次出现的位置为 (注意:这里 对应的是前缀和的下标,即子段的左端点为 ,右端点为 )。
- 对于这个子段 ,执行 DP:
- 否则:
- 更新 的最新出现位置为 。
- 输出 。
第五步:时间复杂度
- 每个前缀和值用哈希表存储,单次操作 。
- 遍历一次数组,总复杂度 。
- 排序或哈希表均可做到 或 ,这里实现为 。
示例验证
示例 1
数组:
前缀和:- 时, 上次出现在 ,子段 和为 ,
- 时, 上次出现在 ,子段 和为 ,
- 时, 上次出现在 ,子段 和为 ,但 ,,,,因为最优是只选 或 中的一个。
最终输出 ,与题意一致。
总结
本题的核心是:
- 转化为前缀和相等问题;
- 使用贪心选择最短子段;
- 用 DP 求最大不重叠区间数。
最终复杂度 。
- 1
信息
- ID
- 7032
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者