Bootstrap

A-B数对(二分查找)

 

#include<bits/stdc++.h>
using namespace std;

using ll = long long;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n,c;
    cin>>n>>c;
    int nu[200000];
    for(int i=0;i<n;i++){
        cin>>nu[i]; // 输入数组元素
    }
    sort(nu,nu+n);
    ll cnt=0; // 统计满足条件的数对数量
    
    for(int i=0;i<n;i++){
        ll a=nu[i]+c;
        
        int l=0,r=n-1;
        ll ans=n; // 初始设为数组长度(表示未找到)
        while(l<=r){
            int mid=l+(r-l)/2;
            if(nu[mid]>=a){
                ans=mid;
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        
        l=0,r=n-1;
        ll res=-1; // 初始设为 -1(表示未找到)
        while(l<=r){
            int mid=l+(r-l)/2;
            if(nu[mid]>a){
                r=mid-1;
            } else{
                res=mid;
                l=mid+1;
            }
        }
        if(ans<=res){
            cnt+=res-ans+1;
        }

    }
    cout<<cnt;
    return 0;
    
    }

输入数组 nu 并对其排序,方便后续通过二分查找快速定位数值。

遍历数组中的每个元素 nu[i],计算目标值 a = nu[i] + c,即寻找数组中大于或等于 a 的第一个位置(起始点)和小于或等于 a 的最后一个位置(结束点)。

两次二分查找

  • 第一次二分查找:找到数组中第一个大于等于 a 的位置。
  • 第二次二分查找:找到数组中最后一个小于等于 a 的位置。
  • 两次查找的结果分别是 ansres

数对的数量为区间长度 res - ans + 1

使用 lower_boundupper_bound:

#include<bits/stdc++.h>
using namespace std;

using ll = long long;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n,c;
    cin>>n>>c;
    int nu[200000];
    for(int i=0;i<n;i++){
        cin>>nu[i];
    }
    sort(nu,nu+n);
    ll cnt=0;
    
    for(int i=0;i<n;i++){
        ll a=nu[i]+c;
        ll ans=lower_bound(nu,nu+n,a)-nu;
        ll res=upper_bound(nu,nu+n,a)-nu-1;
        if(ans<=res){
            cnt+=res-ans+1;
        }
    }
    cout<<cnt;
    return 0;
    
    }

lower_bound(nu, nu + n, a) 返回的是第一个大于或等于 a 的元素的迭代器。

upper_bound(nu, nu + n, a) 返回的是第一个大于 a 的元素的迭代器。由于我们需要找的是小于或等于 a 的最大值,因此在计算 res 时,需要减去 1。

  • ans 是第一个大于等于 a 的位置,使用 lower_bound 获取。
  • res 是最后一个小于等于 a 的位置,使用 upper_bound 获取,然后减去 1。
;