【算法基础】二分

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 单调(只翻一次)
相关推荐
乌萨奇也要立志学C++3 分钟前
【洛谷】BFS 求解最短路:从马的遍历到迷宫问题的实战解析
算法·宽度优先
老鼠只爱大米12 分钟前
LeetCode经典算法面试题 #46:全排列(回溯、交换、剪枝等五种实现方案详细解析)
算法·leetcode·剪枝·回溯·全排列·stj算法
Dovis(誓平步青云)25 分钟前
《滑动窗口算法:从 “暴力遍历” 到 “线性高效” 的思维跃迁》
运维·服务器·数据库·算法
_OP_CHEN1 小时前
【算法基础篇】(五十七)线性代数之矩阵乘法从入门到实战:手撕模板 + 真题详解
线性代数·算法·矩阵·蓝桥杯·c/c++·矩阵乘法·acm/icpc
天天爱吃肉82181 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
im_AMBER1 小时前
Leetcode 114 链表中的下一个更大节点 | 删除排序链表中的重复元素 II
算法·leetcode
xhbaitxl1 小时前
算法学习day38-动态规划
学习·算法·动态规划
多恩Stone1 小时前
【3D AICG 系列-6】OmniPart 训练流程梳理
人工智能·pytorch·算法·3d·aigc
历程里程碑1 小时前
普通数组----轮转数组
java·数据结构·c++·算法·spring·leetcode·eclipse
pp起床1 小时前
贪心算法 | part02
算法·leetcode·贪心算法