GESP5级C++考试语法知识(十、二分算法(二))


🌟《二分王国的三大秘技(竞赛必会)》》

小侦探小明已经学会了普通二分、左边界、右边界。

这一天,老师交给他三张神秘任务卡


🧩 第一种:找"第一个 ≥ target"

1、🎯 故事

宝藏街:

复制代码
1  3  5  7  9

2、👉 任务:找 第一个 ≥ 6 的数

答案应该是:

复制代码
7(位置3)

3、🧠 思想(超级重要)

👉 不是找"等于"

👉 而是找:

复制代码
第一个满足条件的!

4、🧾 模板(最常用!)

复制代码
int lower_bound(int a[], int n, int target)
{
    int left = 0, right = n - 1;
    int ans = n; // 默认不存在

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(a[mid] >= target)
        {
            ans = mid;
            right = mid - 1; // 往左找更小的满足条件
        }
        else
        {
            left = mid + 1;
        }
    }

    return ans;
}

5🎯 一句话记忆

👉 满足条件 → 往左缩!


🧩 第二种:找"第一个 > target"

1、🎯 故事

复制代码
1  3  5  7  9

👉 找 第一个 > 5 的数


答案:

复制代码
7(位置3)

2、🧠 思想

👉 比第一种更严格一点:

复制代码
必须 > target

3、🧾 模板

复制代码
int upper_bound(int a[], int n, int target)
{
    int left = 0, right = n - 1;
    int ans = n;

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(a[mid] > target)
        {
            ans = mid;
            right = mid - 1;
        }
        else
        {
            left = mid + 1;
        }
    }

    return ans;
}

4、🎯 一句话记忆

👉 严格满足 → 往左缩!


🧩 第三种:二分答案

1、🎯 故事

小明遇到一个超级难题:

👉 有一堆木头,要切成 k 段

👉 每段长度尽量长

问:最大长度是多少?


2、🤯 普通想法?

👉 枚举所有长度 ❌(太慢)


3、💡 神奇思路(二分答案!)

👉 答案在一个范围里:

复制代码
长度 ∈ [1, 最大木头长度]

👉 我们可以:

复制代码
猜一个长度 mid
看看"行不行"

4、🧠 核心思想(竞赛灵魂)

👉 把问题变成:

复制代码
这个答案"可不可以"?

👉 如果可以 → 尝试更大

👉 如果不行 → 变小


5、🧾 模板

复制代码
bool check(int mid)
{
    // 判断 mid 是否可行
}

int binary_search_answer()
{
    int left = 1, right = 1000000;
    int ans = 0;

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(check(mid))
        {
            ans = mid;
            left = mid + 1; // 尝试更大!
        }
        else
        {
            right = mid - 1;
        }
    }

    return ans;
}

6、🎯 一句话记忆

👉

复制代码
能行 → 往更大试  
不行 → 往更小试

7、⚖️ 三大变形对比总结

类型 本质 特点
lower_bound 第一个 ≥ 常用于区间
upper_bound 第一个 > 处理重复
二分答案 猜答案 竞赛核心

🧠 最终大脑模型

👉 所有二分题,本质只有两种:


🟢 类型1:找位置

复制代码
数组里找数

✔ lower_bound / upper_bound / 左右边界


🔵 类型2:找答案

复制代码
答案满足单调性

✔ 二分答案(最重要!!)


🎁 竞赛口诀

👉

复制代码
找位置 → 看大小  
找答案 → 看能否

课后训练:竞赛真题


🌟 第1题:切木头(入门之王)


1、🎯 故事

小明有很多木头:

复制代码
8  5  6

他想切成 k = 5 段一样长的小木头

👉 问:每段最长是多少?


2、🧠 思考(关键!)

👉 长度越大 → 能切的段数越少

👉 长度越小 → 能切的段数越多

👉 出现:

复制代码
单调性!(可以二分!)

3、🔍 图解

假设 mid = 3:

复制代码
8 → 2段
5 → 1段
6 → 2段

总共 = 5 ✔

👉 可以!


4、🧾 check函数

复制代码
bool check(int mid)
{
    int cnt = 0;
    for(int i = 0; i < n; i++)
        cnt += a[i] / mid;

    return cnt >= k;
}

5、🧾 完整代码

复制代码
#include <iostream>
using namespace std;

int a[100005];
int n, k;

bool check(int mid)
{
    int cnt = 0;
    for(int i = 0; i < n; i++)
        cnt += a[i] / mid;

    return cnt >= k;
}

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> a[i];

    int left = 1, right = 1000000000;
    int ans = 0;

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(check(mid))
        {
            ans = mid;
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    cout << ans << endl;
}

🌟 第2题:分牛(经典🔥)


1、🎯 故事

有一排牛棚:

复制代码
1   2   8   12   17

要放 3头牛

👉 要让牛之间距离尽量大!


2、🧠 思考

👉 距离越大 → 能放的牛越少

👉 距离越小 → 能放的牛越多

👉 又是:

复制代码
单调性!

3.🔍 图解(mid = 7)

复制代码
放1 → 下一个 ≥8 → 8 ✔  
放8 → 下一个 ≥15 → 17 ✔  

共3头 ✔

4、🧾 check函数(贪心)

复制代码
bool check(int mid)
{
    int cnt = 1;
    int last = a[0];

    for(int i = 1; i < n; i++)
    {
        if(a[i] - last >= mid)
        {
            cnt++;
            last = a[i];
        }
    }

    return cnt >= k;
}

5、🧾 完整代码

复制代码
#include <iostream>
#include <algorithm>
using namespace std;

int a[100005];
int n, k;

bool check(int mid)
{
    int cnt = 1, last = a[0];

    for(int i = 1; i < n; i++)
    {
        if(a[i] - last >= mid)
        {
            cnt++;
            last = a[i];
        }
    }

    return cnt >= k;
}

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> a[i];

    sort(a, a + n);

    int left = 0, right = a[n-1];
    int ans = 0;

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(check(mid))
        {
            ans = mid;
            left = mid + 1;
        }
        else
        {
            right = mid - 1;
        }
    }

    cout << ans << endl;
}

🌟 第3题:抄书问题(经典🔥)


1、🎯 故事

有一排书:

复制代码
10  20  30  40

要给 2个人抄

👉 每人连续抄书,注意是按照顺序连续抄书,一个人抄完,另外一个才能抄书。

👉 求:最大工作量最小


2、🧠 思考

👉 工作量越小 → 需要的人越多

👉 工作量越大 → 人数越少

👉 单调成立!


4、🔍 图解(mid = 60)

复制代码
10+20+30 = 60 一个人✔  
40            一个人 ✔  

共2人 ✔

5、🧾 check函数

复制代码
bool check(int mid)
{
    int cnt = 1, sum = 0;

    for(int i = 0; i < n; i++)
    {
        if(sum + a[i] > mid)
        {
            cnt++;
            sum = a[i];
        }
        else
        {
            sum += a[i];
        }
    }

    return cnt <= k;
}

🧾 完整代码

复制代码
#include <iostream>
using namespace std;

int a[100005];
int n, k;

bool check(int mid)
{
    int cnt = 1, sum = 0;

    for(int i = 0; i < n; i++)
    {
        if(sum + a[i] > mid)
        {
            cnt++;
            sum = a[i];
        }
        else
        {
            sum += a[i];
        }
    }

    return cnt <= k;
}

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> a[i];

    int left = 0, right = 1000000000;
    int ans = right;

    while(left <= right)
    {
        int mid = (left + right) / 2;

        if(check(mid))
        {
            ans = mid;
            right = mid - 1; // 找更小!
        }
        else
        {
            left = mid + 1;
        }
    }

    cout << ans << endl;
}

🧠 三题核心总结

题目 check含义 方向
切木头 能切够吗 ✔ 往大找
分牛 能放下吗 ✔ 往大找
抄书 人够吗 ✔ 往小找

🎯 关键理解

👉 二分答案其实就是:

复制代码
猜答案 + 判断对不对

相关推荐
WolfGang0073211 小时前
代码随想录算法训练营 Day19 | 回溯算法 part01
数据结构·算法
cheems95272 小时前
[数据结构]栈和队列的互相模拟实现
数据结构·算法
cui_ruicheng2 小时前
C++11新特性(中):右值引用与移动语义
开发语言·c++·c++11
计算机安禾2 小时前
【数据结构与算法】第6篇:线性表(二):单链表的实现(头插法、尾插法)
c语言·数据结构·学习·算法·链表·visual studio code·visual studio
2401_873204652 小时前
C++与Node.js集成
开发语言·c++·算法
☆5662 小时前
基于C++的区块链实现
开发语言·c++·算法
liu****2 小时前
5.git标签管理
c++·git·版本控制
ysa0510302 小时前
迷宫传送[最短路径]
c++·笔记·算法·深度优先
计算机安禾2 小时前
【数据结构与算法】第5篇:线性表(一):顺序表(ArrayList)的实现与应用
c语言·开发语言·数据结构·c++·算法·visual studio code·visual studio