1. 程式人生 > 其它 >CF1538C Number of Pairs

CF1538C Number of Pairs

傳送門

\(\texttt{Description}\)

給出序列 \(a\) 以及 \(l\)\(r\),求出 \(l\le a_i+a_j\le r\)\(1\le i<j\le n\)\((i,j)\) 數量。

資料範圍:\(1\le n\le2\times10^5,1\le l\le r\le10^9,1\le a_i\le10^9\)

\(\texttt{Solution}\)

  • 首先暴力是肯定不行的,所以我們要換一種方法。

  • 將序列 \(a\) 從小到大排序。

  • \(l\le a_i+a_j\le r\) 這個不等式拆開來看,不妨設 \(i<j\)

    \(a_i\) 是已知的。

    • \(a_j\ge l-a_i\)

    • \(a_j\le r-a_i\)

  • 所以我們如何確定合法的 \(j\) 的個數呢?自然而然地想到了 lower_boundupper_bound

  • 設對於 \(a_i\) 合法 \(j\) 的左邊界為 \(le\),右邊界為 \(ri\),則:

    • le = lower_bound(a + 1 + i, a + 1 + n, l - a[i]) - a

    • ri = upper_bound(a + 1 + i, a + 1 + n, r - a[i]) - a - 1

  • 那麼答案就是每個 \(a_i\)

    \(ri-le+1\) 之和了。

時間複雜度:\(\mathcal{O}(n\log n)\)

\(\texttt{Code}\)

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

int a[200005];

int main () {
	int T;
	scanf("%d", &T);
	while (T--) {
		int n, l, r;
		scanf("%d %d %d", &n, &l, &r);
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		sort(a + 1, a + 1 + n);
		ll ans = 0;
		for (int i = 1; i < n; i++) {
			int t1 = lower_bound(a + 1 + i, a + 1 + n, l - a[i]) - a;
			int t2 = upper_bound(a + 1 + i, a + 1 + n, r - a[i]) - a;
			ans += 1ll * (t2 - t1);
		}
		printf("%lld\n", ans);
	}
	return 0;
}