upper_bound()和lower_bound函数的基本使用和理解

该博客介绍了如何使用C++和二分查找算法解决三足鼎立问题。通过`lower_bound()`和`upper_bound()`函数,找到满足条件的其他国家数量,从而计算出稳定结盟的组合数。博客解释了为何在特定情况下使用`upper_bound()`和`lower_bound()`,以及为何从`a+i+1`开始搜索,避免重复计算和错误的边界情况。
摘要由CSDN通过智能技术生成

前提:一个非降序列

lower_bound()函数使用:

参数:

1、数组元素的地址(起始搜索位置)e.g. a + i;

2、数组元素的地址(末尾搜索位置)e.g. a + n;

3、二分查找的数

返回值:返回第一次大于等于所查找数的地址

          (在函数后面减去数组名(数组起始地址即可获得下标)


upper_bound()函数

返回值:返回第一个大于查找值的地址

应用例:三足鼎立问题

当三个国家中的任何两国实力之和都大于第三国的时候,这三个国家互相结盟就呈“三足鼎立”之势,这种状态是最稳定的。

现已知本国的实力值,又给出 n 个其他国家的实力值。我们需要从这 n 个国家中找 2 个结盟,以成三足鼎立。有多少种选择呢?

输入格式:

输入首先在第一行给出 2 个正整数 n(2≤n≤105)和 P(≤109),分别为其他国家的个数、以及本国的实力值。随后一行给出 n 个正整数,表示n 个其他国家的实力值。每个数值不超过 109,数字间以空格分隔。

输出格式:

在一行中输出本国结盟选择的个数。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>

using namespace std;

typedef long long  LL;
const int N = 1e5 + 10;
LL a[N], res;

int main()
{
    int n, x;
    cin >> n >> x;
    for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
    sort(a, a + n);
    for(int i = 0; i < n; i++)
    {
        int low = upper_bound(a + i + 1, a + n, abs(x - a[i])) - a;
        int up = lower_bound(a + i + 1, a + n, a[i] + x) - a;
        res += up - low;
    }
    cout << res << endl;
    
    return 0;
}

针对例题进行分析:

1.为什么l用upper而r用lower?

给出两个数x,y,我们需要找abs(x-y)<元素个数<x+y,中的元素个数,所以我们需要先找到第一个比abs(x-y)大的(严格大,没有=号)数的下标,同时这个下标是可以取到的(因为这个下标代表的这个数本身就比abs(x-y)大),这样左边的值我们就找到了,下面需要找右面的值。如果有一串序列是a[]={0,3,3,3,3,4},如果我们在求右边边界值的时候也用upper同时我们x+y在这里为3的话,那我们找的就是a[5],也就是4那个值所在的下标(因为upper是严格大于),但是很明显之前还有很多3,这些3同样是不能取的,因为我们要找的是两边之和大于第三边(严格大于而不是大于等于),所以如果我们用upper的话,我们找到的是严格大于x+y的,我们不确定在严格大于x+y之前有没有和x+y相等的数,这样一来问题就会变得麻烦,所以再求右边边界值的时候我们用lower,即找第一个>=x+y的数,这样一来r-1就一定是最后一个比x+y小的值的下标,同时我们sum+=的时候加的是r-l,这样一来就刚好是这个区间内元素的个数,因为这个区间就是[l,r).

2.为什么upper和lower的时候起始点都是a + i + 1而不是a + 1?

因为会有重复
如果有一下一组数据
7 30
15 16 27 35 42 51 92(顺序已经排好)
如果我们已知两边分别为30和16的话,我们应该找位于区间(14,46)的元素的个数,第一个数字15显然在这个区间中,但是如果按照代码从a + i + 1开始找的话不就找不到15了吗?很明显不会的,因为30 16 15这个组合在找30 15的时候就找完了,也就是说其实并不是30和16找15而是30和15找的16,因为15的位置比16靠前,所以这个组合在之前就已经被找过了,如果我们从a+1开始找的话,那15 16 30这个组合就被找过两次了,所以我们从a+i+1开始找,这样可以避免找到重复的组合。

3.为什么upper和lower的时候起始点都是a + i + 1而不是a + i?

因为a+i+1把a+i这个点排除在外了
例如一个序列 15 16 27 ,我们要已知两边为30和16,那么我们要找的区间就是(14,46),很显然16本身就在这个序列中,但是因为16已经作为一条边出现了,所以我们不能再考虑16,我们需要筛掉它,所以当我们遍历到第i个点时要从a+i+1开始,而不是从a+i开始
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值