洛谷P1102题解(二分搜索法)

我们先看看题目吧!

题目描述

给出一串正整数数列以及一个正整数 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,这里不做赘述,若需要还请查询

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值