1 条题解
-
0
题目概述
给定一个数组 和整数 ,需要将数组分成 个非空子序列。每个子序列的价值定义为:对于子序列中第 个元素,值为 ,取所有 的最大值。
目标:最大化 个子序列价值的总和。
问题分析
关键观察
-
子序列价值计算:如果子序列包含元素 (按原顺序),那么价值为:
-
最优分配策略:为了最大化总价值,我们希望:
- 让"大数"出现在子序列的靠后位置(因为 的加成)
- 让每个子序列尽可能长,但受限于 个子序列的要求
问题转化
实际上,这个问题等价于:
- 选择 个位置进行"分割",将原序列分成 段
- 每段作为一个子序列
- 但注意:子序列不要求连续,所以更灵活
算法思路
核心贪心策略
- 保留最大的 个元素作为各个子序列的"结尾"
- 其余元素分配到各个子序列中,作为前缀
- 总成本 = 所有元素和 + 某种调整项
公式推导
设最终第 个子序列包含 个元素,价值为:
最优情况下,这个最大值通常出现在最后一个元素,因为:
- 可能很大
- 在最后位置最大
所以近似有:第 个子序列价值 ≈
总成本 ≈ = 所有元素和 +
但需要更精确的分析...
算法详解
代码解析
int main() { ios::sync_with_stdio(false); int n, k; cin >> n >> k, k--; // k-- 因为我们要选择k-1个分割点 priority_queue<int, vector<int>, greater<>> q; // 小根堆,维护当前最大的k个元素 long long c = 0, r = 0; // c: 当前堆中元素和, r: 最终答案 for (int i = 0; i < n; i++) { int x; cin >> x; r = max(r, c + x + i + 1); // 关键:计算当前可能的最大值 q.emplace(x), c += x; // 保持堆中只有k个最大元素 if (q.size() > k) c -= q.top(), q.pop(); } cout << r << endl; return 0; }关键公式理解
在位置 (0-indexed),计算:
其中:
- :当前堆中 个最大元素的和
- :当前元素
- :当前位置(1-indexed)
这表示:如果我们在当前位置结束最后一个子序列,那么:
- 前 个子序列的价值和 = (每个子序列以堆中元素结尾)
- 当前子序列价值 = ?需要仔细分析...
正确性证明
实际上,算法基于以下观察:
设我们选择 个元素作为各个子序列的最后一个元素,这些元素的和为 。那么总成本至少为:
因为:
- 每个子序列的最后一个元素贡献
- 所有子序列的长度和为 ,每个位置 贡献
但我们需要最大化的是:
$$\max_{\text{分割方案}} \left(\sum_{i=1}^k \max_{j \in \text{第i个子序列}} (a_j + \text{位置})\right) $$最优解是选择最大的 个元素作为各个子序列的结尾,并且让这些结尾元素尽可能靠后。
样例解析
样例输入
5 3 3 7 10 1 2计算过程
, ,堆中保持2个最大元素
i x 堆变化 c r = max(r, c+x+i+1) 0 3 堆: [3] 3 max(0, 3+3+0+1)=7 1 7 堆: [3,7] 10 max(7, 10+7+1+1)=19 2 10 堆: [7,10], 弹出3 17 max(19, 17+10+2+1)=30 3 1 堆: [7,10] max(30, 17+1+3+1)=22 4 2 max(22, 17+2+4+1)=24 输出:24
验证题目中的分配:
- 子序列1: [3,10] → max(3+1, 10+2) = 12
- 子序列2: [7] → 7+1 = 8
- 子序列3: [1,2] → max(1+1, 2+2) = 4 总和:12+8+4=24 ✓
复杂度分析
- 时间复杂度:
- 每个元素入堆出堆一次,堆操作
- 空间复杂度:
- 堆的大小不超过
对于 可以接受。
算法亮点
- 贪心选择:选择最大的 个元素作为子序列结尾
- 堆维护:动态维护当前最大的 个元素
- 线性扫描:一次遍历解决所有计算
- 公式优化:通过数学观察避免复杂的状态转移
总结
这道题的核心在于理解子序列价值的计算方式,并通过贪心策略最大化总价值:
- 价值分析:子序列价值由 的最大值决定
- 最优结构:让大的数出现在靠后的位置,并且作为子序列的结尾
- 堆的应用:动态维护最优的 个候选
- 一次遍历:在线性时间内解决问题
这种"贪心 + 堆维护"的方法在解决分配和分割问题时非常有效,特别是在需要选择前 大元素的场景下。
-
- 1
信息
- ID
- 4870
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者