蓝桥杯练习022
锻造兵器
题目描述
小明一共有 n 块锻造石,第 i块锻造石的属性值为 ai。
现在小明决定从这 n块锻造石中任取两块来锻造兵器。
通过周密计算,小明得出,只有当两块锻造石的属性值的差值等于 C,兵器才能锻造成功。
请你帮小明算算,他有多少种选取锻造石的方案可以使得锻造成功。
输入描述
第一行包含两个整数 n,C,其含义如题所述。
接下来一行包含 n 个整数,分别表示 a1,a2,…an.
1≤N≤2×105,∣ai∣≤104,0≤C≤10^9。
输出描述
输出共一行,包含一个整数,表示答案。
输入输出样例
示例 1
输入
6 3
8 4 5 7 7 4
输出
5
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路
大佬:这题如果用暴力法统计数对,很显然,复杂度为 O(n^2),超时。所以下面试试尺取法。
萌新:尺取法?em,首先第一步肯定是排序,那么对输入样例排序后得 {4 4 5 7 7 8},其中第一个 4 和后面两个 7 是两对,第二个 4 和后面两个 7 也是两对,共四对。这用尺取法该如何实现?
大佬:如果仅使用 i、j 两个指针,确实是无法实现的,但如果把后面两个 7看成一个整体,一起统计数对,是不是就可以了?我们可以用两个指针 j、k 指示这种区间,[j, k] 区间内每个数都相同,这个区间可以产生 k – j个数对。细节见下面的参考答案。使用三个指针,i 是主指针,从头到尾遍历 n 个数;j、k 是辅助指针,用于查找数字相同的区间 [j, k]。
萌新:哇哦,大佬 nb。
大佬:知道复杂度怎么算吧?
萌新:知道!代码只有一个 for 循环,且 j和 k 随着 i 递增,所以总复杂度为 O(n)。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
int a[N];
int main (){
int n,c;
cin >> n >> c;
for(int i = 1 ; i <= n ; i++)
cin >> a[i];
sort(a + 1 , a + 1 + n);
long long ans = 0; //答案数量超过int,需要用long long
for(int i=1,j=1,k=1; i <= n ; i++) {
while(j <= n && a[j] - a[i] < c )
j++; //用j、k查找数字相同的区间
while(k <= n && a[k] - a[i] <= c)
k++; //区间[j,k]内所有数字相同
if(a[j]-a[i]==c && a[k-1]-a[i]==c && k-1>=1)
ans += k - j; //统计数对
}
cout << ans <<endl;
return 0;
}