C - 最短の登山ルート / Shortest Mountain Climbing Route 解説 by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) points arranged in a line, select a contiguous interval \([l, r]\) such that the sum of absolute elevation differences between adjacent points (total elevation change) is at least \(K\), and minimize the number of points included in such an interval.
Analysis
Key Insight: Using Prefix Sums
Define the absolute elevation difference between adjacent points as \(D_i = |A_{i+1} - A_i|\) (\(i = 0, 1, \ldots, N-2\), 0-indexed). Then, the total elevation change of interval \([l, r]\) (1-indexed) is:
\[\sum_{i=l}^{r-1} |A_{i+1} - A_i| = \sum_{i=l-1}^{r-2} D_i\]
This is a contiguous subarray sum of \(D\). Defining the prefix sum \(S\) of \(D\):
\[S_0 = 0, \quad S_j = D_0 + D_1 + \cdots + D_{j-1}\]
The total elevation change of the interval can be expressed as \(S_{r-1} - S_{l-1}\).
Variable Substitution
Let \(a = l - 1\), \(b = r - 1\), so \(0 \leq a \leq b \leq N - 1\) and: - Total elevation change \(= S_b - S_a\) - Number of points \(= b - a + 1\)
Goal: Minimize \(b - a + 1\) among all \((a, b)\) satisfying \(S_b - S_a \geq K\).
Problem with the Naive Approach
Trying all pairs \((a, b)\) takes \(O(N^2)\), which results in TLE for \(N \leq 2 \times 10^5\).
Key to Optimization
Since \(D_i \geq 0\), \(S\) is monotonically non-decreasing. This property is crucial.
For each \(b\), if we find the largest \(a\) (\(\leq b\)) satisfying \(S_a \leq S_b - K\), then \(b - a + 1\) is minimized. Since \(S\) is monotonically non-decreasing, the set of \(a\) satisfying \(S_a \leq S_b - K\) forms an interval \([0, \text{some value}]\), and we can find the largest such \(a\) in \(O(\log N)\) using binary search.
Concrete Example
For \(A = [1, 5, 3, 8]\), \(K = 5\): - \(D = [4, 2, 5]\), \(S = [0, 4, 6, 11]\) - When \(b = 3\): \(S_3 - K = 6\). The largest \(a\) satisfying \(S_a \leq 6\) is \(2\) (\(S_2 = 6\)). Number of points \(= 3 - 2 + 1 = 2\). - This corresponds to points 3→4 (elevation \(3 \to 8\), elevation change \(5 \geq K\)).
Algorithm
- Compute the array \(D\) of adjacent elevation differences.
- Compute the prefix sum \(S\) of \(D\).
- If the total elevation change over the entire range \(S_{N-1}\) is less than \(K\), output \(-1\) and terminate.
- For each \(b = 0, 1, \ldots, N-1\):
- Compute \(\text{target} = S_b - K\). If \(\text{target} < 0\), skip.
- Use binary search (
bisect_right) among \(S[0], S[1], \ldots, S[b]\) to find the largest \(a\) satisfying \(S_a \leq \text{target}\). - If found, update the answer with \(b - a + 1\).
- Output the minimum answer.
Complexity
- Time complexity: \(O(N \log N)\) (binary search is performed for each \(b\))
- Space complexity: \(O(N)\) (for the prefix sum array)
Implementation Notes
The prerequisite for binary search is that \(S\) is monotonically non-decreasing due to \(D_i \geq 0\). Without this property, binary search cannot be used.
bisect_right(S, target, 0, b+1) - 1finds “the largest \(a\) satisfying \(S_a \leq \text{target}\)”. Sincebisect_rightreturns the first position greater thantarget, subtracting \(1\) gives the largest index that is \(\leq \text{target}\).Since \(K\) can be as large as \(10^{18}\), don’t forget to handle the case where no valid route exists (i.e., the total elevation change over the entire range is less than \(K\)).
Source Code
import sys
from collections import deque
def solve():
input_data = sys.stdin.buffer.read().split()
N = int(input_data[0])
K = int(input_data[1])
A = [int(input_data[i+2]) for i in range(N)]
if N <= 1:
if K <= 0:
print(1)
else:
print(-1)
return
# D[i] = |A[i+1] - A[i]| for i = 0..N-2
D = [abs(A[i+1] - A[i]) for i in range(N-1)]
# prefix sum of D
# S[0] = 0, S[i] = D[0] + D[1] + ... + D[i-1]
S = [0] * N
for i in range(N-1):
S[i+1] = S[i] + D[i]
total = S[N-1]
if total < K:
print(-1)
return
# We want the minimum (r - l + 1) such that S[r] - S[l] >= K
# where 0 <= l < r <= N-1 (using S indices, route is from point l+1 to point r+1...
# Let me re-think the indexing.
# Route (l, r) with 1-indexed points, 1 <= l <= r <= N
# Total elevation = sum_{i=l}^{r-1} |A[i+1]-A[i]| = S[r-1] - S[l-1] (using 0-indexed S where S has N elements)
# Wait, let me redefine clearly.
# Let P[j] = sum of D[0..j-1] for j=0..N-1, so P[0]=0, P[j] = |A[1]-A[0]| + ... + |A[j]-A[j-1]|
# This is exactly S as defined above. S[j] = sum_{i=0}^{j-1} D[i]
# Route from point l to point r (1-indexed): elevation = sum_{i=l}^{r-1} |A[i+1]-A[i]|
# In 0-indexed D: = sum_{i=l-1}^{r-2} D[i] = S[r-1] - S[l-1]
# Number of points = r - l + 1
# Let's substitute: let a = l-1, b = r-1, so 0 <= a <= b <= N-1
# Elevation = S[b] - S[a], points = b - a + 1
# We want S[b] - S[a] >= K, minimize b - a + 1.
# This is equivalent to: for each b, find the largest a <= b such that S[b] - S[a] >= K,
# i.e., S[a] <= S[b] - K. We want to maximize a (to minimize b - a + 1).
# Since S is non-decreasing (D[i] >= 0), we can binary search for each b.
# For each b, find the largest a <= b such that S[a] <= S[b] - K.
# Since S is non-decreasing, S[a] <= S[b] - K means a <= (some threshold).
# The largest such a is found by binary searching for S[b] - K in S[0..b].
import bisect
ans = N + 1
for b in range(N):
target = S[b] - K
if target < 0:
continue
# Find largest a in [0, b] with S[a] <= target
# Since S is non-decreasing, use bisect_right to find insertion point of target
# then the largest index with S[a] <= target is bisect_right(..., target) - 1
idx = bisect.bisect_right(S, target, 0, b + 1) - 1
if idx >= 0:
a = idx
length = b - a + 1
ans = min(ans, length)
if ans > N:
print(-1)
else:
print(ans)
solve()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: