#LC410. 分割数组的最大值
分割数组的最大值
你好,同学。我是你的教练。今天我们要攻克的是一道非常经典、也是信息学竞赛中“二分答案”思想的入门必修题——分割数组的最大值。
在 NOI 竞赛中,这类“最大值最小化”或“最小值最大化”的问题有着极高的出现频率。请拿出草稿纸,随我一起进入思考过程。
一、 预备知识点
- 二分答案(Binary Search on Answer):处理单调性问题的核心工具。
- 贪心算法(Greedy Strategy):用于验证答案是否可行。
- 前缀和(Prefix Sum):快速处理区间和(虽然本题贪心验证时可以直接累加)。
- 动态规划(Dynamic Programming):本题的另一种 解法(在此作为扩展思路)。
二、 题目描述 (NOI 风格)
题目名称:分割数组的最大值 (split_array)
输入文件:split_array.in
输出文件:split_array.out
【问题描述】 给定一个非负整数数组 和一个整数 。你需要将这个数组分割成 个连续的子数组。 设计一个算法,使得这 个子数组各自和的最大值最小。返回这个最小的最大和。
【输入格式】 第一行包含两个整数 和 ,分别表示数组长度和需要分割的子数组数量。 第二行包含 个由空格隔开的非负整数。
【输出格式】 输出一个整数,表示最小的最大子数组和。
【样例 1 输入】
5 2
7 2 5 10 8
【样例 1 输出】
18
【样例 1 说明】
一共有四种方法将 nums 分割为 2 个子数组。其中最佳方案是将数组分割为 [7, 2, 5] 和 [10, 8]。
这两部分和分别为 14 和 18,最大值为 18。
【样例 2 输入】
5 2
1 2 3 4 5
【样例 2 输出】
9
【样例 3 输入】
5 3
1 4 4 10 12
【样例 3 输出】
12
【数据范围限制】
三、 启发式引导:草稿纸上的推演过程
现在,请在你的草稿纸上跟我一起画:
第一步:观察单调性
假设我们要判断:“最大子数组之和是否能不超过 ?”
- 如果 很大(比如所有元素之和),一定能分出来(甚至不需要分 段)。
- 如果 很小(比如比数组里最大的数还小),一定分不出来。
- 结论:随着 的增大,可行性从“不可行”变为“可行”。 这种单调性提示我们:二分 。
第二步:确定二分边界
- 左边界 (Low):数组中的最大值(因为每一段至少要容纳一个数)。
- 右边界 (High):数组所有元素之和(所有数合为一段)。
第三步:贪心验证 (Check 函数)
假设当前二分的值是 mid,我们如何用贪心策略验证?
- 从头开始累加数组元素。
- 如果当前累加和超过了
mid,说明当前这个数必须开启一个新段。 - 统计最后总共分了多少段。
- 如果段数 ,说明 偏大或刚好,可以尝试更小的 ;否则说明 太小。
四、 算法思路流程图 (C++ 伪代码逻辑)
为了避免 Mermaid 语法解析错误,流程图中不使用特殊符号:
graph TD
A(开始) --> B(读取n和k以及数组)
B --> C(确定二分范围 Low和High)
C --> D{Low 小于等于 High}
D -- 否 --> E(输出最终答案)
D -- 是 --> F(Mid 等于 Low加High的一半)
F --> G(调用Check函数验证Mid)
G --> H{Check结果为真}
H -- 是 --> I(记录答案并让High减1)
H -- 否 --> J(让Low加1)
I --> D
J --> D
subgraph Check函数逻辑
K(遍历数组累加当前和) --> L{当前和大于Mid}
L -- 是 --> M(分段数加1并重置当前和为当前元素)
L -- 否 --> N(继续累加)
M --> O(循环结束返回段数是否小于等于k)
N --> O
end
五、 复杂度分析与优化建议
1. 时间复杂度分析:
- 二分次数:。
- 验证函数:每次验证需要遍历一遍数组,复杂度 。
- 总复杂度:。
- 在本题 的规模下,这个复杂度极低,甚至对于 的数据也绰绰有余。
2. 空间复杂度分析:
- 只需存储数组,空间复杂度 。
3. 优化建议:
- 在 NOI 比赛中,如果 很大(例如 ),注意二分时
mid,low,high必须使用long long类型,否则会溢出。 - 贪心验证时,如果某个单元素已经大于
mid,直接判定为不可行。
六、 总结:读题时的关键词
在面对一道新题时,如何快速联想到本题的解法?请关注以下关键词:
- “连续子数组”:这排除了排序的可能,维持了原有的线性顺序。
- “分割成 k 个”:通常暗示 DP 或二分答案。
- “最大值最小化” (Minimize the maximum sum):
- 这是二分答案最明显的标志。
- 类似的表述还有“求最小的可能最大值”、“让最慢的人尽可能快”等。
- “非负整数”:保证了前缀和的单调性,使得贪心验证段数时,段数随
mid的增大而单调递减。
同学,思路理清了吗?现在请尝试在不看参考代码的情况下,手动实现这个 的算法。注意 long long 的使用!加油。