链接:A-B数对
题目描述
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
好吧,题目是这样的:给出一串数以及一个数字 C,要求计算出所有 A - B = C的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个整数 N, C。
第二行,N个整数,作为要求处理的那串数。
输出格式
一行,表示该串数中包含的满足 A - B = C的数对的个数。
输入输出样例
输入
4 1
1 1 2 3
输出
3
说明/提示
对于 75% 的数据,1≤N≤2000。
对于100% 的数据,1≤N≤2×105;
保证所有输入数据绝对值小于 230,且 C≥1。
2017/4/29 新添数据两组
思路1
1,这题是在该数列中,找A,B。使得A-B之差为C;
2,我们由A-B=C,可以变成A=B+C,这样我们可以把一个元素看成B,然后在剩下元素中找B+C即A,然后统计和为B+C的个数;
3,然后把每个元素逐个看成B,找和为B+C的个数;
4,找和为B+C的个数,就是本题要二分完成的,我们可以利用二分找和为B+C的首位置,再找和为B+C的末位置,就可以了;
#include<bits/stdc++.h>
using namespace std;
//A-B=C ==> A=B+C,把每个元素看成B,然后在数组中找B+C的起始位置与终止位置;
const int N=2e5+100;
int q[N];
long long n,m,cnt;//这里会爆int(试了)
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&q[i]);
sort(q+1,q+n+1);//这里要先排序,因为题目没有说是有序的,但是样例却是有序的,就很坑
for(int i=1;i<=n;i++)
{
int b=q[i];
//下面求首次出现B+C 的位置
int l=1,r=n;
while(l<r)
{
int mid=(l+r)/2;
if(q[mid]>=(b+m)) r=mid;
else l=mid+1;
}
int left=l;
//下面求末次出现B+C 的位置
l=1;
r=n;
while(l<r)
{
int mid=(l+r+1)/2;
if(q[mid]<=(b+m)) l=mid;
else r=mid-1;
}
int right=l;
if(q[l]==(b+m))//如果没有找到这个数,意思就是不存在这个数那么就不要
cnt +=(right-left+1);//两次求得 位置之差
}
printf("%lld\n",cnt);
return 0;
}
思路2
1,还有一种直接的,就是把每个元素看成B,然后再剩下找使得A-B差为C;
2,这里就不需要二分找了,但是时间复杂度应该不一样;
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+100;
int arr[N];
int main()
{
int n,c;
scanf("%d%d",&n,&c);
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
sort(arr,arr+n);//排序
int count=0;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(arr[j]-arr[i]==c)
{
count++;//找差为C的个数
}
if(arr[j]-arr[i]>c)
{
break;
}
}
}
printf("%d\n",count);
return 0;
}
总结:
1,善于转化,把题目转化成自己可以理解,容易解决的样子;
2,要注意二分的边界,是否等于,以及等于之后的赋值;
3,勤加练习,后面总结关于二分的介绍,模板等等;