在学习二分算法时了解到了lower_bound()函数与upper_bound()函数。这是c++标准库中的提供的两个非常有用的二分查找函数,定义在
功能:lower_bound
返回指向第一个不小于给定值的元素的迭代器(返回的是一个指针)。
行为:
1,在已排序的[first, last)
范围内查找第一个不小于value
的元素
2,如果所有元素都小于value
,则返回last
3,时间复杂度:O(log n)(对于随机访问迭代器)
示例:
vector v = {1, 2, 4, 4, 5, 6};
auto it = lower_bound(v.begin(), v.end(), 4); // 指向第一个4
auto it2 = lower_bound(v.begin(), v.end(), 3); // 指向第一个4
auto it3 = lower_bound(v.begin(), v.end(), 7); // 返回v.end()
功能:upper_bound
返回指向第一个大于给定值的元素的迭代器(返回的是一个指针)。
行为:
1,在已排序的[first, last)
范围内查找第一个大于value
的元素
2,如果所有元素都不大于value
,则返回last
3,时间复杂度:O(log n)(对于随机访问迭代器)
示例:
vector v = {1, 2, 4, 4, 5, 6};
auto it = upper_bound(v.begin(), v.end(), 4); // 指向5
auto it2 = upper_bound(v.begin(), v.end(), 6); // 返回v.end()
特性 | lower_bound | upper_bound |
---|---|---|
查找条件 | 第一个不小于value | 第一个大于value |
返回值 | 可能等于value | 一定大于value |
典型用途 | 查找插入位置(保持有序) | 查找范围上界 |
1,查找元素是否存在:
bool exists = binary_search(v.begin(), v.end(), value);
// 等价于
bool exists = lower_bound(v.begin(), v.end(), value) != v.end() &&
*lower_bound(v.begin(), v.end(), value) == value;
2 ,统计某值的出现次数:
int count = upper_bound(v.begin(), v.end(), value) -
lower_bound(v.begin(), v.end(), value);
3,在有序序列中插入元素:
v.insert(lower_bound(v.begin(), v.end(), new_value), new_value);
这两个函数是高效操作有序序列的基础工具,在竞赛编程和实际工程中都有广泛应用。
在当时的deepseek回答完我之后,我就产生了一个疑惑,lower_bound和upper_bound这两个函数的功能不会重复吗?在经过深度的思考过后,我终于明白了这两个函数的设计不是重复的,而是互补的,它们一起可以精确确定一个值在有序序列中的范围。
下面提供一个相关的题:P8667 [蓝桥杯 2018 省 B] 递增三元组 - 洛谷
给定三个整数数组 A=[A1,A2,⋯,AN],B=[B1,B2,⋯,BN],C=[C1,C2,⋯,CN]。
请你统计有多少个三元组 (i,j,k) 满足:
第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,⋯,AN。
第三行包含 N 个整数 B1,B2,⋯,BN。
第四行包含 N 个整数 C1,C2,⋯,CN。
一个整数表示答案
输入 #1
3 1 1 1 2 2 2 3 3 3
输出 #1
27
如题所示,该题可以先将a,b,c三个数组进行排序。由数学关系不难看出,递增三元组的个数即对于数组b中的每一位数字,寻找在数组a中小于其数的个数乘以,在数组c中大于其数的个数。所以就可以从1到n进行遍历,在数组a中寻找小于b[i]的数的个数,在数组c中寻找大于b[i]的数的个数,然后再将它们相乘并累加起来,即可得到最终的答案。
由此思路,就可以把b[i]当作所寻找的值,利用lower_bound和upper_bound来分别在数组a和数组b中小于和大于s[i]的数的个数。
具体代码如下:
#include
#include
#include
using namespace std;
int main()
{
int n;
long long res = 0;
cin>>n;
vector a(n),b(n),c(n);
for (int i = 0;i < n;++i){
cin>>a[i];
}
for (int i = 0;i < n;++i){
cin>>b[i];
}
for (int i = 0;i < n;++i){
cin>>c[i];
}
sort(a.begin(),a.end());
sort(c.begin(),c.end());
for (int i = 0;i < n;++i){
//cnt1为数组a中第一个等于b[i]的数组下标,即小于b[i]的数量
long long cnt1 = lower_bound(a.begin(),a.end(),b[i]) - a.begin();
//cnt2为数组c中第一个大于b[i]的数组下标,n - cnt2即为大于b[i]的个数
long long cnt2 = upper_bound(c.begin(),c.end(),b[i]) - c.begin();
//累加结果
res += cnt1 * (n - cnt2);
}
cout<