洛谷-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 新添数据两组

  题目分析

  1. 数据规模N最大为2e5,普通查找方式肯定会超时,我们可以先对序列排序,然后用二分查找查找数据。
  2. A – B = C可知,A、B是变量C是常量,那么我们知道A就可以通过C求B,转化式子为:A – C = B。
  3. A是输入数据中的序列,C是具体数,B是A – C的结果。通过A – C得到的B作为key(要查找的关键词),在原序列中去寻找是否存在。
  4. 遍历时每次判断得到B是否存在,用一个计数器来记录存在次数,遍历完序列后输出。
  5. 关键的小坑:待查的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)

原文地址:https://www.cnblogs.com/kirk-notes/p/14994865.html