洛谷題解——P1102:A-B 數對

題目相關

題目鏈接

洛谷,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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章