【算法基础】二分

1. 整数二分模板


整数二分是求红色范围的右端点 或者 绿色范围的左端点

红色区间最右侧的那个点即是:序列中最后一个满足某条件(红色条件)的元素

绿色区间最左侧的那个点即是:序列中第一个不满足某条件(红色条件)的元素或是第一个满足某条件(绿色条件)的元素

定义check条件。如果判断mid < target, 那么找到的是小于target但是最接近target的数,就是小于target的最大数。如果判断mid >= target, 那么找到的是大于或者等于target的最接近target的数,就是target或者比target大的最小数。


cpp 复制代码
模板:

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 找右区间最左端点
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}

// 找左区间最右端点
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
cpp 复制代码
#include <iostream>

using namespace std;

const int N = 1e5 + 10;
int arr[N];

int main()
{
    int n, q;
    scanf("%d%d", &n, &q);
    for (int i = 0; i < n; i++) scanf("%d", &arr[i]);

    while (q--)
    {
        int l = 0, r = n - 1, x, mid;
        scanf("%d", &x);
        // 1 2 2 3 3 4 找第一个3即右区间最左端点
        while (l < r)
        {
            mid = l + r >> 1;
            if (arr[mid] >= x) r = mid;
            else l = mid + 1;
        }
        if (arr[l] != x) // 若找不到
            cout << "-1 -1" << endl;
        else // 找左区间的最右端点
        {
            cout << l << " " ;
            l = 0, r = n - 1;
            while (l < r)
            {
                int mid = l + r + 1 >> 1;
                if (arr[mid] <= x) l = mid;
                else r = mid - 1;
            }
            cout << r << endl;
        }
        
    }
    return 0;
}

2. 浮点数二分模板

cpp 复制代码
bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

A. 方程求根类(最直观)

题 1:求解方程根(单调)

给定实数 a,ba,ba,b(保证存在唯一解),求方程x3+x=ax^3 + x = ax3+x=a的解,输出保留 6 位小数。
check 设计x^3 + x >= a(左边随 x 严格递增,单调)。

题 2:对数/指数方程

给定 a>0a>0a>0,求满足
ln⁡(1+x)=a \ln(1+x)=a ln(1+x)=a

的 xxx(唯一解),保留 6 位小数。
checklog(1+x) >= a(单调递增)。
区间l=0, r=...(可取大一点,例如 r=1e6)


B. "最小值/最大值 + 可行性"类(最常见的二分答案)

题 3:最小时间完成任务(机器生产)

有 nnn 台机器,第 iii 台每生产 1 件需要 tit_iti 秒。问最少多少秒能生产至少 MMM 件?输出保留 6 位小数(允许机器连续生产,时间是实数)。
check(T) :计算 ∑⌊T/ti⌋≥M\sum \lfloor T/t_i \rfloor \ge M∑⌊T/ti⌋≥M 是否成立。

  • 单调性:T 越大能生产越多,更容易满足(false→true)。

这是经典"最小时间"模型,整数/浮点都能做,若题目允许连续或要求小数,就用浮点二分。

题 4:最小加油速度(到达不晚)

你要在 DDD 公里内赶到,最晚时间 TTT 小时。车速 vvv 可取实数,问最小 vvv 使得 D/v≤TD/v \le TD/v≤T。
check(v)D / v <= T(v 越大越容易满足)。


C. 几何覆盖/距离类(半径、距离、阈值)

题 5:最小半径覆盖所有点(圆覆盖)

给定平面上 nnn 个点,和一个固定圆心 CCC。求最小半径 RRR,使得圆心为 CCC 的圆覆盖所有点。
check® :判断所有点到 CCC 的距离是否都 ≤R\le R≤R。

  • 单调性:R 越大越容易覆盖。

(这题其实能直接算最大距离,但它是让你练"浮点二分 + 单调覆盖"的直觉。)

题 6:一维点用 k 个区间覆盖(最小区间长度)

给定数轴上 nnn 个点,允许用 kkk 个长度为 LLL 的闭区间覆盖所有点。求最小 LLL。
check(L) :贪心从左到右放区间,看能否用 ≤k\le k≤k 个覆盖完。

  • 单调性:L 越大越容易覆盖。

D. 最大化某个"比值/平均值"的经典套路

题 7:最大平均值子段(或选 k 个物品的最大平均)

给定数组 a1..ana_1..a_na1..an,求长度至少为 mmm 的连续子段最大平均值,输出 6 位小数。
二分答案 avg

把每个数变成 bi=ai−avgb_i = a_i - avgbi=ai−avg,问是否存在长度 ≥ m 的子段使得 ∑bi≥0\sum b_i \ge 0∑bi≥0。
check(avg):用前缀和 + 最小前缀判定是否存在这样的子段。

  • 单调性:avg 越大越难达到(true→false 或反过来,取决于你写的 check)。

这是"二分答案 + 判定"的代表题型之一,含金量很高。

题 8:最大化单位成本收益(分数规划)

有 n 个项目,第 i 个项目收益 pip_ipi、成本 cic_ici,你必须选恰好 k 个项目,最大化 ∑p∑c\frac{\sum p}{\sum c}∑c∑p。
二分 ratio

令 bi=pi−ratio⋅cib_i = p_i - ratio \cdot c_ibi=pi−ratio⋅ci,问是否能选 k 个使得 ∑bi≥0\sum b_i \ge 0∑bi≥0。
check(ratio) :把所有 bib_ibi 排序取最大的 k 个看和是否 ≥ 0。

  • 单调性:ratio 越大越难满足。

E. 物理/概率/连续过程类

题 9:混合浓度(最小倒入量达到目标浓度)

有两种溶液浓度 c1,c2c_1,c_2c1,c2,你要混合成浓度至少为 CCC,其中第一种倒入量为 xxx(实数),总量固定为 VVV。求最小 xxx。
check(x):混合浓度是否 ≥ C(关于 x 线性单调)。


你做题时的"识别口诀"

看到这些特征就该想到浮点二分:

  1. 答案是实数(要保留若干位小数 / 允许误差)
  2. 能写 check(x):给定 x 判断"可不可以/行不行/是否满足不等式"
  3. check 随 x 单调(只翻一次)
相关推荐
Lips6111 小时前
2026.1.11力扣刷题笔记
笔记·算法·leetcode
charlie1145141912 小时前
从 0 开始的机器学习——NumPy 线性代数部分
开发语言·人工智能·学习·线性代数·算法·机器学习·numpy
执携3 小时前
算法 -- 冒泡排序
数据结构·算法
寻星探路3 小时前
【算法专题】滑动窗口:从“无重复字符”到“字母异位词”的深度剖析
java·开发语言·c++·人工智能·python·算法·ai
wen__xvn4 小时前
代码随想录算法训练营DAY14第六章 二叉树 part02
数据结构·算法·leetcode
Ka1Yan4 小时前
[数组] - 代码随想录(2-6)
数据结构·算法·leetcode
漫随流水5 小时前
leetcode算法(104.二叉树的最大深度)
数据结构·算法·leetcode·二叉树
机器学习之心HML5 小时前
鲸鱼算法(WOA)优化Kriging模型
算法
DYS_房东的猫5 小时前
《 C++ 零基础入门教程》第6章:模板与 STL 算法 —— 写一次,用万次
开发语言·c++·算法