洛谷题单指南-二分查找与二分答案-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;
}