📏

二分答案

答案藏在一堆候选值里?先问"行不行",再二分

💡 打个比方

题目:"3 根绳子剪出等长的至少 4 段,最长能剪多长?"答案不是现成的,但一定在某个范围(比如 1~100)里。

别一个个试!写一个裁判 check(x):"剪 x 厘米,够 4 段吗?"如果 x 可行,比 x 短的一定也可行(剪得越短段数越多)——可行答案连成一片。于是二分:猜中间值,问裁判,砍掉一半,几轮就逼到边界。

二分答案三要素:① 答案在 [L, R] 范围内;② 写出 check(x) 判断"答案取 x 行不行";③ check 必须单调——可行的 x,比它小的都可行(或都不可行)。答案就是"可行"与"不可行"的边界。复杂度 O(log R × check 的代价)。

🖼️ 大图看明白

① 在答案范围 [1,100] 上二分,check 裁判说了算 第 1 轮:[1,100] mid=50 ✗ 太长 → r=50 第 2 轮:[1,50] mid=25 ✓ 可行 → l=25 第 3 轮:[25,50] mid=37 ✓ 可行 → l=37 第 4 轮:[37,50] mid=43 ✗ 太长 → r=43 第 5 轮:[37,43] 继续减半… → l、r 逼近 答案:最大的可行值 = 38 ② 前提:check 必须单调——可行答案连成一片 可行(剪短了更够) 不可行(剪长了不够) 边界 = 答案 = 38 check 一次 O(n),二分约 log(R) 轮,总复杂度 O(n log R)——比逐个试快得多

📏 二分答案,只要 3 步

  1. 第 1 步:定答案范围。想清楚答案一定在 [L, R] 里(比如剪出的长度在 1 ~ 最长那根绳子之间)。
  2. 第 2 步:写裁判 check(x)。判断"答案取 x 行不行"(比如:所有绳子按 x 剪,总段数 ≥ 要求的段数?)。check 必须单调:x 可行 ⇒ 更小的 x 也可行。
  3. 第 3 步:二分逼边界。check(mid) 可行 → 记录 ans = mid,往更大找(l = mid + 1);不可行 → 往更小找(r = mid - 1)。l > r 时结束,ans 就是最大可行答案。
防死循环:用 [l, r] 闭区间 + l <= r + 两边都"跳过 mid"(l = mid + 1 / r = mid - 1),范围严格缩小,必然结束。记住:可行的 mid 要记下来再往右找,因为答案可能就是它。

💻 C++ 怎么写

// 3 根绳子剪出至少 4 段等长,求最长(厘米,整数)
int lens[] = {30, 45, 60};

bool check(int x) {          // 裁判:剪 x 厘米,够 4 段吗?
    int cnt = 0;
    for (int i = 0; i < 3; i++) cnt += lens[i] / x;
    return cnt >= 4;
}

int main() {
    int l = 1, r = 60, ans = 0;     // 答案范围 [1, 60]
    while (l <= r) {
        int mid = l + (r - l) / 2;
        if (check(mid)) {
            ans = mid;              // 可行,记下来
            l = mid + 1;            // 试试更长
        } else {
            r = mid - 1;            // 不可行,改短
        }
    }
    cout << ans << endl;      // 30
    return 0;
}
考点提醒:① 求"最大值"→ 可行往右、不可行往左;求"最小值"则反过来(可行往左、不可行往右);② check 里 30/30=1、45/30=1、60/30=2 共 4 段刚好够,所以答案是 30;③ 整数答案用闭区间,实数答案要限定迭代轮数。

✋ 你来试试

题 1:为什么 check(x) 必须单调?如果"可行"不连成一片会怎样?
二分每次"砍一半"都建立在"可行答案全在一边"上:check(mid) 可行时,我们放心地把答案往更大找;不可行时,放心地往更小找。如果可行答案是跳着出现的(比如 10 可行、20 不可行、30 又可行),check(mid) 的结果就没法告诉我们答案在哪半边,二分立刻失灵。
题 2:check(mid) 可行时,为什么 l = mid + 1 而不是 l = mid?
因为用闭区间 [l, r] 时,mid 本身也是候选答案:可行说明 mid 可以要,先记 ans = mid,再去 [mid+1, r] 里找"能不能更长"。如果 l = mid,下一轮 mid 还是同一个值,范围缩不了,就死循环了。同理不可行时 r = mid - 1。
🎯 一句话记住:二分答案 = 范围 + 裁判 check + 二分;check 必须单调(可行连成一片);可行记答案再往大找,答案就是边界。