1. 二分查找算法基础与COCI题目解析
二分查找(Binary Search)是一种在有序数组中查找特定元素的高效算法,时间复杂度为O(log n)。这个算法通过不断将搜索区间减半来快速定位目标元素,相比线性搜索的O(n)时间复杂度,在处理大规模数据时优势明显。
在C++中,标准模板库(STL)提供了三种常用的二分查找相关函数:
- binary_search:检查元素是否存在
- lower_bound:查找第一个不小于目标值的位置
- upper_bound:查找第一个大于目标值的位置
以题目P9029 [COCI 2022/2023 #1] Čokolade为例,这是一道典型的二分查找应用题。题目大意是:给定n块巧克力,每块有不同的甜度值,需要将它们分成k组,使得每组甜度之和的最大值最小化。这正是经典的"最大值最小化"问题,非常适合用二分查找解决。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二分查找的STL实现详解
2.1 binary_search函数使用
binary_search函数的基本形式为:
cpp复制bool found = binary_search(arr.begin(), arr.end(), target);
这个函数在有序区间[first, last)内查找target,返回bool值表示是否存在。需要注意的是:
- 容器必须是有序的(通常为升序)
- 对于自定义类型,需要提供比较函数或重载<运算符
- 只返回是否存在,不返回具体位置
典型应用场景:
cpp复制vector<int> nums = {1, 3, 5, 7, 9};
bool hasFive = binary_search(nums.begin(), nums.end(), 5); // true
bool hasSix = binary_search(nums.begin(), nums.end(), 6); // false
2.2 lower_bound和upper_bound
这两个函数返回的是迭代器(指针),需要特别注意:
cpp复制// lower_bound: 第一个不小于target的元素位置
auto it = lower_bound(arr.begin(), arr.end(), target);
int pos = it - arr.begin();
// upper_bound: 第一个大于target的元素位置
auto it = upper_bound(arr.begin(), arr.end(), target);
int pos = it - arr.begin();
实际应用示例:
cpp复制vector<int> nums = {1, 2, 2, 3, 4, 4, 4, 5};
// 查找第一个不小于3的元素
auto lb = lower_bound(nums.begin(), nums.end(), 3);
cout << *lb; // 3
cout << lb - nums.begin(); // 3
// 查找第一个大于4的元素
auto ub = upper_bound(nums.begin(), nums.end(), 4);
cout << *ub; // 5
cout << ub - nums.begin(); // 7
2.3 自定义比较函数
对于复杂数据结构,可以自定义比较函数:
cpp复制struct Chocolate {
int sweetness;
// 其他属性...
};
vector<Chocolate> chocs = {...};
// 按甜度排序
sort(chocs.begin(), chocs.end(),
[](const Chocolate& a, const Chocolate& b) {
return a.sweetness < b.sweetness;
});
// 查找特定甜度的巧克力
auto it = lower_bound(chocs.begin(), chocs.end(), targetSweetness,
[](const Chocolate& c, int val) {
return c.sweetness < val
