题目内容
给定一个长度为 n n n 的数组 a a a ,找到有多少不同的下标对 ( i , j ) , i ≠ j (i,j), i\neq j (i,j),i=j ,满足 l ≤ a i + a j ≤ r l\leq a_i+a_j\leq r l≤ai+aj≤r 。
数据范围
- 1 ≤ n ≤ 2 ⋅ 1 0 5 1\leq n\leq 2\cdot 10^5 1≤n≤2⋅105
- 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1≤ai≤109
- 1 ≤ l ≤ r ≤ 1 0 9 1\leq l\leq r\leq 10^9 1≤l≤r≤109
题解
首先下标只要不同即可,所以先对数组排序。
枚举下标 i i i ,对于数 a i a_i ai ,
- 找到 j 1 > i j_1>i j1>i 的最小的 j 1 j_1 j1 ,满足 a i + a j 1 ≥ l a_i+a_{j_1}\geq l ai+aj1≥l
- 找到 j 2 > i j_2>i j2>i 的最大的 j 2 j_2 j2 ,满足 a i + a j 2 ≤ r a_i+a_{j_2}\leq r ai+aj2≤r
那么对于 a i a_i ai ,就有 j 2 − j 1 + 1 j_2-j_1+1 j2−j1+1 个下标 j j j 使得 l ≤ a i + a j ≤ r l\leq a_i+a_j\leq r l≤ai+aj≤r
当然后面的部分也可以使用双指针,不过时间复杂度的瓶颈在于排序。
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, x, y;
cin >> n >> x >> y;
vector<int> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
sort(a.begin(), a.end());
long long ans = 0;
for (int i = 0; i < n - 1; ++i) {
if (a[i] + a[n - 1] < x) continue;
if (a[i] + a[i + 1] > y) continue;
int l = i + 1, r = n - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (a[i] + a[mid] >= x) r = mid;
else l = mid + 1;
}
int left = l;
l = i + 1, r = n - 1;
while (l < r) {
int mid = (l + r + 1) >> 1;
if (a[i] + a[mid] <= y) l = mid;
else r = mid - 1;
}
ans += r - left + 1;
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}