1 条题解
-
0
问题重述
给定序列 ,可以执行一次操作:选择区间 和整数 ,将区间内所有数加上 。要求最大化最终序列的众数出现次数,并找出所有可能成为众数的值。
关键观察
1. 操作的本质
操作相当于:我们可以将任意一个连续区间内的数整体平移到另一个值。
这意味着:
- 我们可以让某个区间内的数都变成同一个目标值
- 目标值可以是任意整数(受 范围限制,但范围很大)
2. 问题转化
设目标众数值为 。我们希望通过操作,让尽可能多的数等于 。
对于每个位置 :
- 如果 ,那么它自然就是 ,不需要修改
- 如果 ,我们可以通过修改包含 的区间,将 变成
关键限制:所有被修改的位置必须在同一个连续区间内。
核心解法
1. 按数值分组
首先,将序列中所有等于某个值 的位置找出来。设 是 出现的所有位置。
我们的目标是:对于每个候选值 ,计算通过一次区间修改,最多能让多少个位置变成 。
2. 区间修改的收益分析
假设我们选择目标值为 ,考虑哪些位置可以变成 :
- 原本就是 的位置:直接贡献
- 原本是其他值的位置:如果它们在一个连续的修改区间内,且通过加上某个 能变成 ,那么也可以贡献
重要性质:对于固定的目标值 ,一个值 能通过区间修改变成 当且仅当 对于某个 成立。但由于 可以任意选择,实际上任何值都可以通过区间修改变成 !
因此,问题简化为:选择一个区间 ,让区间内的所有数都变成 ,同时区间外的 保持不变。
算法框架
1. 问题重新表述
对于候选值 ,设:
- = 在原始序列中的出现次数
- 我们选择一个区间 ,区间内原本不是 的数通过修改变成
- 区间外原本是 的数保持不变
那么最终 的出现次数 = + - (区间内原本是 的个数)
2. 最大化策略
对于固定的 ,定义序列 :
- 如果 ,则 (修改这个位置会减少 的数量)
- 如果 ,则 (修改这个位置会增加 的数量)
那么问题转化为:在 序列中找一个区间 ,使得区间和最大。
这是一个经典的最大子段和问题!
3. 最终计算
对于值 ,最大出现次数 = + (最大子段和)
我们需要对所有不同的 计算这个值,然后取最大值。
具体实现
1. 预处理
- 用哈希表记录每个值出现的位置
- 对每个值 ,构建对应的 序列
2. 最大子段和计算
使用 Kadane 算法在 时间内计算最大子段和:
def max_subarray_sum(arr): max_ending_here = max_so_far = 0 for x in arr: max_ending_here = max(0, max_ending_here + x) max_so_far = max(max_so_far, max_ending_here) return max_so_far3. 对所有值计算
对于每个值 :
- 如果 出现次数很少,直接构建 序列计算
- 如果 出现次数很多,可以优化:实际上只需要在 出现的位置附近计算
复杂度优化
直接对每个值构建 序列是 的,不可行。
关键优化:实际上,我们只需要考虑那些在序列中出现过的值作为候选目标值。
对于每个候选值 ,我们只需要在它的出现位置附近计算最大子段和,因为:
- 序列中只有 出现的位置是 ,其他位置是
- 最大子段和一定出现在某个 出现位置的附近
具体来说,我们可以:
- 对序列离散化
- 对每个值 ,记录所有出现位置
- 对于每个 ,在 的附近窗口内计算最大子段和
边界情况
1. 全序列相同
题目保证 不全相等,所以不需要特殊处理。
2. 最大出现次数为
如果最大子段和 = ,说明可以通过一次修改让所有数变成 。
3. 多个值达到最大出现次数
需要记录所有达到最大出现次数的 值。
最终算法
- 离散化:将 映射到
- 分组:记录每个值出现的位置
- 计算最大值:
- 初始化 ,
- 对每个值 :
- 在 的出现位置附近计算最大子段和
- 如果 ,更新 和
- 如果 ,将 加入
- 输出: 和排序后的
复杂度分析
- 离散化:
- 最大子段和计算:每个值 的处理与它的出现次数相关,总复杂度
- 总复杂度:,适合
总结
这道题的核心在于:
- 问题转化:将区间修改问题转化为最大子段和问题
- 收益分析:分析修改不同位置对目标值出现次数的影响
- 算法优化:利用出现位置的局部性优化计算
- 多候选处理:找出所有可能达到最大出现次数的值
通过将复杂的区间操作问题转化为经典的最大子段和问题,我们得到了一个高效且优雅的解法。
- 1
信息
- ID
- 4456
- 时间
- 3000ms
- 内存
- 1024MiB
- 难度
- 9
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者