410. 分割数组的最大值
考点
- 划分DP
- 贪心
- 二分
思路
3599. 划分数组得到最小 XOR的姐妹题,两道题建议同时对比学习
划分DP
令:
- \(a_1, a_2, \dots, a_n\) 为原数组;
- \(f[j][i]\):把前 \(i\) 个数 \(a_1..a_i\) 划分成 恰好 \(j\) 段 时, 所有段和中的最大值的 最小可能值。
记区间和: \[
\text{sum}(l, r) = a_l + a_{l+1} + \dots + a_r
\] 转移写成数学形式就是: \[
f[j][r]
= \min_{j \le l \le r} \max\bigl(f[j-1][l-1],\ \text{sum}(l,r)\bigr)
\] 为什么只用f[j-1][l-1]呢?道理很简单
假设我当前子数组的和为5,而前面子数组的最大和分别有4、6
5与4取max得到的是5,5与6取max得到的是6,那么答案应该选择5才对
这就意味着,我们只需要保存前面子数组最大和的最小值即可,如果该最小值小于等于5,那么我们就会取5
如果该最小值大于5,那么我们就会取该最小值
可以得到如下AC代码:
1 | class Solution { |
本题不同于3599. 划分数组得到最小 XOR,用二分更优
二分
设计
我们关心的答案是:
把数组分成 k 段后,所有段的「段和中的最大值」最小是多少?
设这个值为 X。有个关键单调性:
- 如果我能用 不超过 k
段,把数组分成若干段,并且每一段的和都 ≤
X, 那么对于任何Y >= X,也一定能做到(约束变宽松了)。 - 如果连
X都做不到(无论怎么切,总会有一段和 > X), 那么对于任何Y < X,更不可能做到。
所以「能否在 ≤k 段内,使每段和 ≤ mid」这个条件对 mid
是单调的,可以二分。
判定
判定函数:给定 mid,能否在 ≤k 段内满足「每段和 ≤ mid」?
贪心做法:
- 从左到右扫数组,用
cur记录当前这一段的和,用cnt记录段数(初始 1 段)。 - 每来一个
x:- 若
cur + x <= mid:继续放在当前段:cur += x; - 否则:开新的一段:
++cnt; cur = x;
- 若
- 扫完后,看
cnt是否 ≤k:- ≤ k:说明在约束
mid下能完成拆分 → 返回true; - 否则说明这个
mid太小,段数不够用 → 返回false。
- ≤ k:说明在约束
注意一个细节:如果存在某个
nums[i] > mid,那么无论怎么切,都会有一段至少包含它,所以这一段的和一定
> mid,直接 false。但我们二分的时候下界就设为
max(nums[i]),这样自然不会出现这种情况。
二分范围
- 下界
L = max(nums[i]):最小也得容得下单个元素; - 上界
R = sum(nums[i]):最大就是不切分,整个数组一段。
在 [L, R] 上二分最小的可行值。
可以得到如下代码:
1 | class Solution { |