#LC875. 爱吃香蕉的珂珂

爱吃香蕉的珂珂

你好,同学。我是你的 OI 教练。今天我们要攻克的是一道非常经典、也是 NOI 竞赛中“二分答案”专题的必修题——爱吃香蕉的珂珂

在信息学奥赛中,当我们遇到“求某个值的最小可能值,且该值具有单调性”的问题时,二分答案几乎是标准动作。请拿出草稿纸,随我一起拆解这道题。


一、 预备知识点

  1. 二分答案 (Binary Search on Answer):将求解问题转化为判定性问题。
  2. 单调性 (Monotonicity):吃香蕉的速度越快,所需的时间越短。
  3. 向上取整技巧:计算一堆香蕉需要多少小时时,a/b\lceil a/b \rceil 可以写成 (a + b - 1) / b
  4. 时间复杂度分析:理解 O(NlogM)O(N \log M) 的效率优势。

二、 题目描述 (NOI 风格)

题目名称:爱吃香蕉的珂珂 (koko) 输入文件koko.in 输出文件koko.out

【问题描述】 珂珂喜欢吃香蕉。这里有 nn 堆香蕉,第 ii 堆中有 piles[i]piles[i] 根香蕉。警卫已经离开了,将在 hh 小时后回来。 珂珂可以决定她吃香蕉的速度 kk(单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 kk 根。如果这堆香蕉少于 kk 根,她将吃光这堆香蕉,并且这一小时内不会再吃更多的香蕉。 珂珂喜欢慢慢吃,但仍然希望能在警卫回来前吃完所有的香蕉。 请你编写一个程序,求出她能在 hh 小时内吃完所有香蕉的最小整数速度 kk

【输入格式】 第一行包含两个整数 nnhh,分别表示香蕉堆数和警卫回来的时间。 第二行包含 nn 个由空格隔开的正整数,表示每堆香蕉的数量 piles[i]piles[i]

【输出格式】 输出一个整数,表示最小的吃香蕉速度 kk

【样例 1 输入】

4 8
3 6 7 11

【样例 1 输出】

4

【样例 2 输入】

5 5
30 11 23 4 20

【样例 2 输出】

30

【样例 3 输入】

5 6
30 11 23 4 20

【样例 3 输出】

23

【数据范围限制】

  • 1n1041 \le n \le 10^4
  • nh109n \le h \le 10^9
  • 1piles[i]1091 \le piles[i] \le 10^9

三、 启发式引导:草稿纸上的推理过程

请在草稿纸上跟我一起画:

1. 寻找单调性

  • 如果珂珂以 1010 根/小时的速度能吃完,那么以 1111 根/小时的速度一定也能吃完。
  • 如果珂珂以 55 根/小时的速度吃不完,那么以 44 根/小时的速度一定更吃不完。
  • 这种“可行性”随速度增加而从“不可行”变为“可行”的性质,就是单调性

2. 确定二分的值域 [L, R]

  • 左边界 L:最小速度是 11
  • 右边界 R:最大速度其实不需要超过数组中的最大值(因为每小时只能吃一堆,速度再快也得花 nn 小时)。

3. 判定函数 (Check)

假设珂珂当前的速度是 midmid,计算总耗时:

  • 对于每一堆 pp,所需时间是 p/mid\lceil p / mid \rceil
  • 累加所有堆的时间,如果总和 h\le h,说明速度 midmid 合法。

四、 算法思路流程图 (C++ 14 伪代码逻辑)

graph TD
    A(开始) --> B(读取n和h以及数组piles)
    B --> C(设置L等于1, R等于数组中的最大值)
    C --> D{L 小于 R}
    D -- 否 --> E(输出最终答案L)
    D -- 是 --> F(Mid 等于 L加R的一半)
    F --> G(计算以速度Mid吃完所需的总时间Total)
    G --> H{Total 是否小于等于 h}
    H -- 是 --> I(速度够快, 尝试更小的速度: R等于Mid)
    H -- 否 --> J(速度太慢, 必须加速: L等于Mid加1)
    I --> D
    J --> D

    subgraph Check函数逻辑
    K(遍历piles数组) --> L(当前堆耗时等于 -p加Mid减1- 除以 Mid)
    L --> M(累加到Total)
    M --> K
    end

五、 复杂度分析与优化建议

1. 时间复杂度

  • 二分次数log(max(piles))\log(\max(piles)),由于 piles[i]109piles[i] \le 10^9,二分大约进行 3030 次。
  • 判定函数:每次判定需要遍历一次数组,复杂度 O(N)O(N)
  • 总复杂度O(NlogM)O(N \log M),其中 N=104N=10^4M=109M=10^9。总运算量约为 3×1053 \times 10^5,在 NOI 1秒时限内绰绰有余。

2. 空间复杂度

  • 存储数组需要 O(N)O(N) 空间。

3. 优化建议与易错点

  • 数据范围:虽然 piles[i]piles[i]int 范围内,但累加的总时间 Total 可能会超过 23112^{31}-1。在判定函数中建议使用 long long 存储时间总和,防止溢出。
  • 向上取整:避免使用 doubleceil(),在竞赛中浮点数精度可能带来风险。使用 (p + mid - 1) / mid 是更稳健的整数技巧。

六、 总结:读题关键词

在面对 NOI 题目时,看到以下描述应立即联想到二分答案:

  1. “求最小的整数速度...”:典型的最优化问题。
  2. “每个小时只能吃一堆”:限定了判定的逻辑(贪心判定)。
  3. “速度越快时间越短”:隐含的单调性条件。
  4. 数据范围对比nn 较小 (10410^4),但 hhpiles[i]piles[i] 很大 (10910^9),说明不能直接枚举时间或速度。

同学,思路清晰了吗?现在请在草稿纸上尝试写出 check 函数的具体实现。注意 long long 的使用!加油。