C - 中継局の設置 / Installation of Relay Stations 解説 by admin
Claude 4.6 Opus (Thinking)Overview
This problem asks you to select 2 or more locations from candidate sites on a road to install relay stations, such that the distance between any two adjacent relay stations is at most \(D\), while minimizing the total construction cost.
Analysis
Key Insight: The Optimal Solution Always Consists of a Pair of 2 Points
First, let’s sort the candidate sites by coordinate.
Core observation: In the optimal solution, it is always sufficient to select exactly 2 locations.
This is because, if there exists a valid solution selecting \(k \geq 2\) locations, then any two coordinate-adjacent points among them have distance at most \(D\). Selecting only that adjacent pair still forms a valid solution, and its cost is at most the original solution’s cost (since the costs of the other points are positive).
In other words, this problem can be rephrased as:
Among all pairs \((i, j)\) whose coordinate difference is at most \(D\), find the minimum value of \(C_i + C_j\).
Naive Approach
Checking all pairs takes \(O(N^2)\), which results in TLE for \(N = 2 \times 10^5\).
Optimization
If we sort by coordinate, then for each point \(i\), the set of points “\(j < i\) satisfying \(X_i - X_j \leq D\)” forms a contiguous interval. We need to efficiently find the minimum \(C_j\) within this interval, which can be done in \(O(N)\) using a sliding window minimum (monotonic queue).
Algorithm
- Sort the candidate sites in ascending order of coordinates.
- While maintaining a left pointer, for each point \(i\), do the following:
- Add point \(i-1\) to the window (update the monotonic queue).
- Remove points from the left end of the window where \(X_i - X_j > D\).
- If the queue is not empty, compute \(dp_i = C_i + C_{\text{queue front}}\) (= minimum cost within the window).
- The minimum value of \(dp_i\) across all \(i\) is the answer. If no valid pair exists, output
-1.
Concrete Example
For \(N=3, D=5\), with points \((0, 100), (5, 1), (10, 100)\):
- \(i=1\) (coordinate 5): Window contains the point at coordinate 0. \(5-0=5 \leq 5\) → \(dp = 1 + 100 = 101\)
- \(i=2\) (coordinate 10): Window contains points at coordinates 0 and 5. \(10-0=10 > 5\), so remove the point at coordinate 0. \(dp = 100 + 1 = 101\)
Answer: \(101\)
Complexity
- Time complexity: \(O(N \log N)\) (dominated by sorting; the sliding window is \(O(N)\))
- Space complexity: \(O(N)\)
Implementation Notes
Monotonic queue (deque): Store indices in the queue, and remove elements from the back as long as
C[dq[-1]] >= C[i-1]before adding, so that the front always holds the point with the minimum cost within the window.Window management: The window for point \(i\) consists of points “to the left of \(i\) and within distance \(D\)”. Note that point \(i\) itself is not included in the window; it is added when processing the next point.
-1determination: If no adjacent pair has distance at most \(D\), no valid solution exists, so output-1.Source Code
import sys
from collections import deque
def main():
input_data = sys.stdin.buffer.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
D = int(input_data[idx]); idx += 1
points = []
for i in range(N):
x = int(input_data[idx]); idx += 1
c = int(input_data[idx]); idx += 1
points.append((x, c))
# Sort by coordinate
points.sort()
if N < 2:
print(-1)
return
# dp[i] = minimum cost of a valid selection where point i is the LAST (rightmost) relay station
# We need at least 2 stations selected.
#
# For each point i, we can either:
# 1. Start a new chain: point i is paired with some point j < i where X[i] - X[j] <= D
# cost = C[i] + C[j] -> we want min C[j] for j in valid range
# 2. Extend an existing chain: dp[i] = C[i] + min(dp[j]) for j where X[i] - X[j] <= D
#
# Actually, let's define:
# dp[i] = minimum total cost of a valid selection (>=2 stations) where station i is the rightmost
#
# dp[i] = C[i] + min over j in window { min(dp[j], C[j]) }
# where window = { j : j < i and X[i] - X[j] <= D }
#
# Because if we pick j as the previous station:
# - If j already has a chain ending at it (dp[j] is valid), cost contribution from left part is dp[j]
# - If j is the start of a new pair with i, cost contribution is C[j]
# - So we want min(dp[j], C[j]) over valid j
#
# dp[j] >= C[j] always (since dp[j] includes C[j] plus at least one more station's cost)
# So min(dp[j], C[j]) = C[j] always!
#
# Wait, that's not right. dp[j] = cost of chain ending at j with >=2 stations, which includes C[j].
# So dp[j] >= C[j] + (cost of at least one other station) > C[j].
# Therefore min(dp[j], C[j]) = C[j].
#
# So dp[i] = C[i] + min(C[j]) for j in window where X[i] - X[j] <= D and j < i.
# And dp[i] is valid (represents a chain of >=2) whenever such j exists.
#
# Wait, but this would mean we always just pick pairs? No - because the chain constraint requires
# ALL consecutive selected stations to be within D. If we select {a, b, c} with a < b < c,
# we need b-a <= D AND c-b <= D. So it's not just about pairs.
#
# The issue: if we select a subset S, ALL consecutive gaps must be <= D.
# So if we pick the pair (j, i) that's fine - cost C[j] + C[i].
# If dp[j] represents a valid chain ending at j, and X[i] - X[j] <= D, then we can extend it.
# Cost = dp[j] + C[i].
#
# We want the minimum over all valid chains. The answer is min(dp[i]) for all i.
#
# dp[i] = C[i] + min over j in window { min(dp[j], C[j]) }
# Since dp[j] >= 2*min_cost > C[j] is NOT necessarily true if C[j] is large...
# Actually dp[j] includes C[j] + at least one more C value, so dp[j] > C[j] if costs are positive.
# Since C[j] >= 1, dp[j] >= C[j] + 1 > C[j]. So indeed min(dp[j], C[j]) = C[j].
#
# Therefore dp[i] = C[i] + min{C[j] : j < i, X[i] - X[j] <= D}
# Answer = min(dp[i]) over all valid i, or -1.
INF = float('inf')
X = [p[0] for p in points]
C = [p[1] for p in points]
# Sliding window minimum of C[j] for j in window [left, i-1] where X[i] - X[j] <= D
ans = INF
# Use a deque for sliding window minimum of C values
dq = deque() # stores indices, C[dq[0]] is the minimum in window
left = 0
for i in range(N):
# Add point i-1 to the window (if i > 0)
if i > 0:
while dq and C[dq[-1]] >= C[i-1]:
dq.pop()
dq.append(i-1)
# Remove points out of window from front
while dq and X[i] - X[dq[0]] > D:
dq.popleft()
if dq:
dp_i = C[i] + C[dq[0]]
if dp_i < ans:
ans = dp_i
print(ans if ans < INF else -1)
main()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: