洛谷-P1102 A-B 数对
题目描述
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
好吧,题目是这样的:给出一串数以及一个数字 C,要求计算出所有 A - B = C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个整数 N, C。
第二行,N个整数,作为要求处理的那串数。
输出格式
一行,表示该串数中包含的满足 A - B = C 的数对的个数。
输入输出样例
输入#1 |
输出#1 |
4 1 1 1 2 3 |
3
|
说明/提示
对于 75% 的数据,1≤N≤2000。
对于 100% 的数据,1≤N≤2e5。
保证所有输入数据绝对值小于 2^30。
2017/4/29 新添数据两组
题目分析
- 数据规模N最大为2e5,普通查找方式肯定会超时,我们可以先对序列排序,然后用二分查找查找数据。
- A – B = C可知,A、B是变量C是常量,那么我们知道A就可以通过C求B,转化式子为:A – C = B。
- A是输入数据中的序列,C是具体数,B是A – C的结果。通过A – C得到的B作为key(要查找的关键词),在原序列中去寻找是否存在。
- 遍历时每次判断得到B是否存在,用一个计数器来记录存在次数,遍历完序列后输出。
- 关键的小坑:待查的B结果可能不止一个,所以查找还得查出B在序列中有几个。此处可以用下面陈述的代码,有空用C++中STL里的函数upper_bound()和lower_bound函数来确定左右边界,差值即为B的个数(函数快捷入口)。
可行代码
#include <algorithm> #include <iostream> using namespace std; int search(int key, int *arr, int len) { int l = -1, r = len - 1, mid; // 注意的是数组是从0开始的 while (l + 1 < r) { mid = l + r >> 1; if (arr[mid] <= key) l = mid; else r = mid; } return r; // 返回第一个大于key的位置 } int main() { int NumCount, AimNum; // 序列长度、C的值 cin >> NumCount >> AimNum; int num[NumCount]; for (int i = 0; i < NumCount; i++) cin >> num[i]; long long Sum = 0; // 数据很大 sort(num, num + NumCount); // 二分查找的前提是序列有序 for (int i = 0; i < NumCount; i++) { int begin = search(num[i] - AimNum - 1, num, i + 1); // 左边界 int end = search(num[i] - AimNum, num, i + 1); // 右边界 Sum += end - begin; // 每次查找结果叠加 } cout << Sum << endl; return 0; }
END 感谢reader's阅读,洛谷题目链接:P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)