C - ボーナスエリア付きダーツ / Darts with Bonus Area Editorial by admin
GPT 5.2 HighOverview
We need to efficiently determine whether each distance \(D_i\) falls within any bonus interval \([L_j, R_j]\), and for each throw that does, add an extra \(D_i\) points to the total score.
Analysis
The score for each throw is \(2D_i\) if it lands in a bonus area, and \(D_i\) otherwise. Therefore, the total score can be computed as: - First, sum up \(D_i\) for all throws (the base score). - Then, for each throw that lands in a bonus area, “add an extra \(D_i\).”
This simplifies the problem.
The core challenge is determining whether \(D_i\) is contained in any of the \(M\) intervals, and doing this \(N\) times.
Why the naive approach is too slow
If we check all intervals \([L_j, R_j]\) for each \(D_i\), the worst case is \(O(NM)\). Since \(N, M \le 2\times 10^5\), this would be on the order of \(4\times 10^{10}\) operations, which is too slow.
How to solve it (key insight)
Even if intervals overlap, we only need to know “whether \(D_i\) is inside any of them.” Therefore, if we sort the bonus intervals and merge overlapping ones in advance, we obtain a sequence of non-overlapping intervals.
Example: - \([1, 5], [3, 7], [10, 12]\) after merging becomes - \([1, 7], [10, 12]\)
Once the intervals are non-overlapping, we can use binary search to quickly find which interval each \(D_i\) might belong to.
Algorithm
- Sort the \(M\) input intervals \([L_j, R_j]\) in ascending order of \(L_j\).
- Scan from left to right, merging overlapping (or adjacent) intervals to create a non-overlapping interval sequence
merged.- If the left endpoint \(l\) of the new interval is greater than the right endpoint of the previous interval (\(l > prev\_r\)), add it as a separate interval.
- Otherwise, they overlap, so extend the right endpoint to \(\max(prev\_r, r)\).
- Extract
starts(left endpoints of each interval) andends(right endpoints of each interval) as arrays frommerged. - Compute the total score as follows:
total = sum(Ds)(base score for all throws)- For each \(d \in Ds\), perform a binary search on
startsto find “the interval with the largest start that is \(\le d\).” Specifically,k = bisect_right(starts, d) - 1. - If \(k \ge 0\) and \(d \le ends[k]\), then \(d\) is contained in that interval, so add the bonus:
extra += d. - Output
total + extraas the final answer.
Why this check is correct:
- starts is sorted in ascending order and the intervals are non-overlapping, so the only interval that could contain \(d\) is “the one with the largest start point that is \(\le d\).”
- If \(d\) is within that interval’s right endpoint ends[k], it is inside; otherwise, it is outside.
Complexity
- Time complexity: \(O(M\log M)\) for sorting the intervals and \(O(N\log M)\) for checking each throw, giving \(O((N+M)\log M)\) overall.
- Space complexity: \(O(M)\) for the interval arrays and merge results.
Implementation Notes
By merging intervals in advance, each check becomes just “one binary search + one comparison.”
The result of
bisect_right(starts, d) - 1can be-1(i.e., all start values are greater than \(d\)), so ak >= 0check is necessary.The maximum score is at most \(2 \times \sum D_i\), so there is no overflow concern with Python’s
int.Since the input can be large, it is safer to read it quickly using
sys.stdin.buffer.read()as shown in the provided code.Source Code
import sys
from bisect import bisect_right
def main():
data = sys.stdin.buffer.read()
ndata = len(data)
idx = 0
def ni():
nonlocal idx
while idx < ndata and data[idx] <= 32:
idx += 1
num = 0
while idx < ndata and data[idx] > 32:
num = num * 10 + (data[idx] - 48)
idx += 1
return num
N = ni()
M = ni()
Ds = [ni() for _ in range(N)]
intervals = [(ni(), ni()) for _ in range(M)]
intervals.sort()
merged = []
for l, r in intervals:
if not merged or l > merged[-1][1]:
merged.append([l, r])
else:
if r > merged[-1][1]:
merged[-1][1] = r
starts = [lr[0] for lr in merged]
ends = [lr[1] for lr in merged]
total = sum(Ds)
extra = 0
for d in Ds:
k = bisect_right(starts, d) - 1
if k >= 0 and d <= ends[k]:
extra += d
print(total + extra)
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: