洛谷题单指南-二分查找与二分答案-P1102 A-B 数对

原题链接:https://www.luogu.com.cn/problem/P1102

题意解读:寻找A-B=C的数对数量,C大于0,B一定比A小,枚举B,找A是否存在即可。

解题思路:

先将数据由小到大排序,接下来介绍两种方法:二分、双指针

1、二分

枚举第1~n-1个数,作为B,寻找A=B+C的数量,只需要通过二分查找第一A和最后一个A的位置l、r,数量为r-l+1,进行累加即可。

100分代码:

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

const int N = 200005;

int a[N], n, c;
long long ans;

int bs1(int x)
{
    int res;
    int l = 1, r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(a[mid] >= x) res = mid, r = mid - 1;
        else l = mid + 1;
    }
    if(a[res] == x) return res;
    return -1;
}

int bs2(int x)
{
    int res;
    int l = 1, r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(a[mid] <= x) res = mid, l = mid + 1;
        else r = mid - 1;
    }
    if(a[res] == x) return res;
    return -1;
}

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

    sort(a + 1, a + n + 1);

    for(int i = 1; i < n; i++)
    {
        int A = a[i] + c;
        int l = bs1(A), r = bs2(A);
        if(l != -1 && r != -1) ans += r - l + 1;
    }
    cout << ans;

    return 0;
}

2、双指针

指针i从1开始所指元素a[i]表示B,指针j从2开始所指元素a[j]表示A,

如果a[j]-a[i]<C,j往后走

如果a[j]-a[i]>C,i往后走

如果a[j]-a[i]=C,计算相同的a[j]、a[i]有多少个,相乘即为当前A-B=C数对的数量,累加即可

100分代码:

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

const int N = 200005;

int a[N], n, c;
long long ans;

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

    sort(a + 1, a + n + 1);

    for(int i = 1, j = 2; i < n; i++) //双指针,i从1开始,j从2开始,a[i]表示B,a[j]表示A
    {
        while(a[j] - a[i] < c && j <= n) j++; //如果A-B<C,j往后走
        if(a[j] - a[i] == c) //如果A-B=C
        {
            int cntA = 1, cntB = 1;
            while(a[i + 1] == a[i] && i + 1 < n) i++, cntB++; //找B的数量,i移到相同值的最后一个
            while(a[j + 1] == a[j] && j + 1 <= n) j++, cntA++; //找A的数量,j移到相同值的以后一个
            ans += 1ll * cntA * cntB; //cntA * cntB即当前A-B=C的对数
        } 
    }

    cout << ans;

    return 0;
}

 

posted @ 2024-02-29 11:56  五月江城  阅读(51)  评论(0编辑  收藏  举报