E - ペアの選定 / Choosing Pairs Editorial by admin Editorial for printing
Claude Opus 5 (High)Overview
This problem asks us to count the number of pairs \((i,j)\) chosen from \(N\) people such that \(A_i+A_j \ge X\) and \(B_i+B_j \ge Y\). Since \(N \le 10^5\), enumerating all pairs in \(O(N^2)\) will result in TLE, so we reduce the time complexity to \(O(N\log N)\) using sorting + binary search + BIT (Fenwick tree).
Analysis
Naive Approach
If we check all pairs \((i,j)\) using a double loop, the number of pairs is approximately \(\frac{N^2}{2} = 5\times 10^9\), which will definitely result in TLE.
Transforming the Condition by Fixing One Element
Fixing member \(i\), the conditions become:
- \(A_j \ge X - A_i\)
- \(B_j \ge Y - B_i\)
This forms “two lower bound conditions on \(j\)”. In other words, this problem reduces to counting the number of points \((A_j,B_j)\) on a 2D plane that fall into the upper-right quadrant (2D dominance counting).
If there were only one condition (for example, only on \(A\)), we could simply sort \(A\) and use binary search. However, with two conditions, simple sorting alone cannot determine “the number of elements that also satisfy the condition on \(B\) among the set satisfying the condition on \(A\),” so we need a cleverer approach.
Solution Strategy: Process One in Sorted Order, Manage the Other with a BIT
First, sort the points in ascending order of \(A\). Then, as we iterate through \(i\) in increasing order of \(A\), the
\[\text{threshold } thr = X - A_i\]
decreases monotonically. Therefore, “the set of \(j\) satisfying \(A_j \ge thr\)” forms a contiguous suffix from the end of the sorted array, and this interval only expands (never shrinks) as \(i\) increases.
Therefore, by using a two-pointer approach to progressively add “points satisfying the condition on \(A\)” into a BIT, and querying the BIT to count how many among the inserted points satisfy \(B_j \ge Y - B_i\), we can compute the answer for each \(i\) in \(O(\log N)\).
Handling Duplicates and Self-Pairs
With this counting method, both \((i,j)\) and \((j,i)\) are counted (as ordered pairs). Furthermore, self-pairs where \(j=i\) are also counted if they satisfy the conditions (\(2A_i \ge X\) and \(2B_i \ge Y\)). Therefore, we can compute:
\[\text{Answer} = \frac{(\text{Total counted}) - (\text{Number of elements satisfying the condition with themselves})}{2}\]
Since the conditions are symmetric with respect to \(i\) and \(j\), this formula holds.
Algorithm
- Sort the points \((A_i,B_i)\) in ascending order of \(A\) to obtain arrays
AandB. - Coordinate compress the values of
B(since values can be up to \(10^9\), they cannot be used directly as BIT indices). Letusbe the sorted array of unique values inB, andrank[i]be the rank ofB[i](1-indexed). - Initialize a BIT (of size \(m=|us|\), tracking the count at each position) and set pointer
p = n(elements from indexponwards are already inserted). - For \(i = 0,1,\dots,N-1\) in order:
- Set
thr = X - A[i]. WhileA[p-1] >= thr, decrementpand add \(+1\) to the BIT at that point’srank. - Set
t = Y - B[i], findidx = bisect_left(us, t)(which is the number of values where \(B < t\)), and query the BIT to finds, the “number of inserted points where \(B < t\)”. - Since the total number of inserted points is
n - p, the number of points satisfying the condition is(n - p) - s. Add this tototal.
- Set
- Count the number of indices \(i\) where \(2A_i \ge X\) and \(2B_i \ge Y\), denoted as
self_. - Output
(total - self_) // 2.
Example
When \(N=3, X=5, Y=5\), and the points are \((1,4),(3,3),(4,2)\) (already in ascending order of \(A\)):
- \(i=0\): \(thr=4\) \(\to\) insert \((4,2)\). \(t=5-4=1\) \(\to\) there is 1 point with \(B\ge1\).
total=1 - \(i=1\): \(thr=2\) \(\to\) insert \((3,3)\) (inserted: \(\{2,3\}\)). \(t=2\) \(\to\) 2 points.
total=3 - \(i=2\): \(thr=1\) \(\to\) insert \((1,4)\) (inserted: \(\{2,3,4\}\)). \(t=3\) \(\to\) 2 points with \(B\ge3\).
total=5 - Self-pairs: only \((3,3)\) (\(6\ge5, 6\ge5\)) \(\to\)
self_=1 - Answer: \((5-1)/2 = 2\)
Indeed, the pairs satisfying the conditions are \(\{(1,4),(4,2)\}\) (sums \(5,6\)) and \(\{(3,3),(4,2)\}\) (sums \(7,5\)), which gives 2 pairs, matching our result.
Complexity
- Time Complexity: \(O(N \log N)\) (sorting, binary search for coordinate compression, and each BIT operation take \(O(\log N)\);
pmoves at most \(N\) times in total) - Space Complexity: \(O(N)\)
Implementation Notes
Do not rewind pointer
p: SortingAin ascending order makes the threshold monotonically decrease, soponly ever decreases. Thus, points are inserted at most \(N\) times in total. Note that sorting in reverse order would break this monotonicity.Coordinate compression: Since \(B_i \le 10^9\), it cannot be used directly as a BIT index. Compress it using
sorted(set(B))and find ranks usingbisect_left.Counting “\(B \ge t\)”: Since a BIT excels at prefix sums, we first find
idx = bisect_left(us, t)(the number of compressed positions with \(B<t\)), compute the sumson the BIT interval \([1,\,idx]\) (the “number of inserted points with \(B<t\)”), and take(total inserted) - s. If \(t \le 0\),idx = 0, correctly yielding all inserted elements.Converting from ordered to unordered pairs: Do not forget to subtract self-pairs and divide by 2 at the end. Since \(X\) and \(Y\) can be up to \(2\times10^9\), and \(2A_i\) can be similarly large, 64-bit integers should be used in languages like C++ (the answer itself can also reach about \(5\times10^9\)).
Fast I/O: Since there are \(N=10^5\) lines of input, reading everything at once with
sys.stdin.buffer.read().split()in Python is recommended. For the BIT as well, inlining loops instead of function calls can be faster.Source Code
import sys
from bisect import bisect_left
def main():
data = sys.stdin.buffer.read().split()
n = int(data[0]); X = int(data[1]); Y = int(data[2])
pts = sorted((int(data[3 + 2 * i]), int(data[4 + 2 * i])) for i in range(n))
A = [p[0] for p in pts]
B = [p[1] for p in pts]
us = sorted(set(B))
m = len(us)
rank = [bisect_left(us, b) + 1 for b in B]
tree = [0] * (m + 1)
p = n
total = 0
for i in range(n):
thr = X - A[i]
while p > 0 and A[p - 1] >= thr:
p -= 1
k = rank[p]
while k <= m:
tree[k] += 1
k += k & -k
t = Y - B[i]
idx = bisect_left(us, t)
s = 0
k = idx
while k > 0:
s += tree[k]
k -= k & -k
total += (n - p) - s
self_ = 0
for i in range(n):
if 2 * A[i] >= X and 2 * B[i] >= Y:
self_ += 1
sys.stdout.write(str((total - self_) // 2) + "\n")
main()
This editorial was generated by claude5opus-high.
posted:
last update: