题目相关
题目链接
洛谷,https://www.luogu.com.cn/problem/P1102。
我的OJ,http://47.110.135.197/problem.php?id=4759。
题目描述
给出一串数以及一个数字 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×10^5。
保证所有输入数据都在 32 位带符号整数范围内。
题目分析
题意分析
在一个数列中,找出所有 A-B=C 的组合。
样例数据分析
有 4 个数据的数列,从中找出所有差值为 1 的数据组合。输入的数列为:1 1 2 3。我们可以知道:
1、第三个数据 2 减去第一个数据 1,两者之差为 1。
2、第三个数据 2 减去第二个数据 1,两者之差为 1。
3、第四个数据 3 减去第三个数据 2,两者之差为 1。
因此总计有 3 组数据。
数据规模分析
1、根据题目描述,保证所有输入数据都在 32 位带符号整数范围内,因此用 int 可以表示。
2、N 的最大范围是 2e5。这个有什么用?只有当数据 A 的总个数和数据 B 的总个数只差为 1 的时候,答案是最大的。就是我们如果有这样一组输入数据:
10 1
1 1 1 1 1 2 2 2 2 2
如果上面的数据,有 5 个 1、5 个 2,这样最后的答案为 5*5=25。
也就是说,我们的输出结果最大的范围是 (n/2)*(n/2),也就是 10^5*10^5=10^10。
说明我们需要用 long long 或者 unsigned long long 来表示结果。
注意:在乘积的过程中,可能导致 int 溢出。
模拟算法
算法思路
1、读入数。
2、统计每个数出现的数量。
3、排序。
4、去重。
5、计算结果。
该算法的核心是如何对所有的数据个数进行统计。
方法一:采用数组来统计,数组的大小是 2^32 个。这个方法明显比较浪费。
方法二:使用 STL 中的 map 来统计。
AC 参考代码
/*
OJ:MYOJ
题号:4759
题目:A-B 数对
地址:http://47.110.135.197/problem.php?id=4759
*/
#include <bits/stdc++.h>
const int MAXN = 2e5+2;
int arr[MAXN];
int main() {
std::map<int, int> myMap;
int n;
int c;
scanf("%d %d", &n, &c);
int i;
for (i=0; i<n; i++) {
scanf("%d", &arr[i]);
myMap[arr[i]]++;//当前数的个数++
}
std::sort(arr, arr+n);//排序
n = std::unique(arr, arr + n) - arr;//去重
//统计
unsigned long long ans = 0;
for (i=0; i<n; i++) {
if ((myMap[arr[i]] && myMap[arr[i]-c])) {
ans += ((unsigned long long)myMap[arr[i]] * myMap[arr[i]-c]);
}
}
printf("%llu\n", ans);
return 0;
}
细节讲解
1、我们必须排序。因为题目没有告诉我们数据是有序的。
2、通过统计个数后,重复的元素就可以删除了。
3、注意计算 ans 的时候,先要将 int 的数据类型强制转换为 unsigned long long,否则两个 int 乘法可能导致溢出。比如输入有 2e5个数据,C 为 1,数列中有 1e5 个 1 和 1e5 个 2。这样我们的答案是 10^5*10^5=10*10,而样例代码中的 map 中保存的是 int 类型,将导致数据溢出。
二分查找
算法思路
1、读入数。
2、排序。
3、从头开始二分查找。我们有了 A 和 C,就可以在数列中查有几个 B。也就是查找数据 B 的左下界和右上界。
AC 参考代码
/*
OJ:MYOJ
题号:4759
题目:A-B 数对
地址:http://47.110.135.197/problem.php?id=4759
*/
#include <bits/stdc++.h>
const int MAXN = 2e5+2;
int arr[MAXN];
int main() {
int n;
int c;
scanf("%d %d", &n, &c);
int i;
for (i=0; i<n; i++) {
scanf("%d", &arr[i]);
}
std::sort(arr, arr+n);//排序
//统计
unsigned long long ans = 0;
for (i=0; i<n; i++) {
int b = arr[i]-c;
int lo = std::lower_bound(arr, arr+n, b) - arr;
int hi = std::upper_bound(arr, arr+n, b) - arr;
if (lo!=hi || arr[lo]==b) {
ans += (hi-lo);
}
}
printf("%llu\n", ans);
return 0;
}