我们先看看题目吧!
题目描述
给出一串正整数数列以及一个正整数 CC,要求计算出所有满足 A - B = CA−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N,C这。
第二行,N个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A - B = C 的数对的个数。
输入输出样例
输入
4 1 1 1 2 3
输出
3
这个题我们可以把A - B = C给他转换成A - C =B,为什么要这么换呢?
- C是我们自己定义的一个数字,相当于是已知的
- A是我们接下来要在循环中遍历的数字,相当于是已知的
- 原来的A和B我们都不知道,一个式子有两个未知数,这样不利于解题,但是经过转换之后,相当于这个式子里只有一个未知数B了
我们通过循环遍历数组,并且把这个数字给A,那么这道题相当于就变成了每给一个A,寻找B的个数,经过这样一个转换,二分搜索就浮出水面了,接下来我们只需要去用二分搜索找B的个数即可
先上代码:
#include<iostream>
#include<algorithm>
using namespace std;
int N , C;
int a[200010];
int researchLeft(int l , int r , int B)
{
while(l<r)
{
int mid = (l + r)/2;
if(a[mid] < B)l = mid + 1;
else r = mid;
}
return l;
}
int researchRight(int l,int r,int B)
{
while(l<r)
{
int mid = (l + r + 1)/2;
if(a[mid] > B)r = mid - 1;
else l = mid;
}
return r;
}
int main()
{
scanf("%d %d",&N,&C);
for(int i = 1 ; i <= N ; i ++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+N+1);
long long ans = 0;
for(int i = 1 ; i <= N ; i ++)
{
int A = a[i];
int B = A - C;
int left = researchLeft(1,i-1,B);
int right = researchRight(1,i-1,B);
if(a[left] == B)
{
ans += right - left + 1;
}
}
printf("%lld", ans);
return 0;
}
下面我来大概介绍一下,因为本人在遍历数组的时候喜欢从下标为0的地方开始遍历(这样也符合数组首元素的下标为0这个特性),但是在二分搜索中我们最好是用1来表示数组第一个元素,然后依次类推(这样方便计算)
注意:我们只找小于A的那一部分数组,因为题目中说了所有数字都是整数,那么A-C的结果必然是小于A的,所以找B只用在小于A的那一部分数组中找
给两个函数传参的时候,分别传入数组的第一个元素的下标1,数组最后一个元素的下标i-1(是i-1的原因是遍历数组的时候是从i=1开始遍历的),还有要找的数字B。
然后在函数体里的东西就是死的了,只需要记住就行,切记:函数体里的东西得记住
PS:代码中有一个排序的库函数sort,这里不做赘述,若需要还请查询