題目相關
題目鏈接
洛谷,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;
}