E - 山頂コレクション / Peak Collection 解説 by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) mountain peaks, select at most \(K\) of them such that their altitudes are strictly increasing and the total entrance fees are within budget \(B\), maximizing the number of peaks climbed. This can be described as finding the “Longest Strictly Increasing Subsequence (LIS) with a budget constraint.”
Analysis
Naive Approach
The first idea that comes to mind is to enumerate all subsequences and find the longest one satisfying the conditions, but the number of subsequences can be up to \(2^{500}\), which is far too many to handle.
Key Insight
This problem has three axes:
- Number of selected mountains \(k\) (at most \(K\))
- Total cost spent \(b\) (at most \(B\))
- Altitude of the last selected mountain (the next mountain must have a strictly higher altitude)
In the standard LIS problem, we “maximize the count,” but here a budget constraint is added. Therefore, we consider a DP that holds the count \(k\) and cost \(b\) as states, and minimizes the “altitude of the last selected mountain.”
Why “Minimize the Last Altitude”?
The smaller the altitude of the last selected mountain, the more candidate mountains can be chosen in the future, increasing the possibility of climbing more peaks. In other words, for the same state \((k, b)\), a smaller last altitude is always advantageous (or at least equivalent).
Algorithm
DP Definition
\(dp[k][b]\) = Among all strictly increasing altitude sequences of exactly \(k\) mountains with a total entrance fee of exactly \(b\) yen, the minimum altitude of the last mountain.
- Initial value: \(dp[0][0] = -\infty\) (the state where no mountain has been selected; use \(-1\) or similar as a sentinel). All other values: \(dp[k][b] = +\infty\) (unreachable).
Transition
We process the mountain peaks in order \(i = 1, 2, \ldots, N\). For mountain peak \(i\) with cost \(C_i\) and altitude \(S_i\):
\[dp[k][b] = \min(dp[k][b],\ S_i) \quad \text{if } dp[k-1][b - C_i] < S_i\]
Here, to avoid using the same mountain twice, we loop \(k\) from large to small and \(b\) from large to small (reverse-order loop as in the 0-1 knapsack).
Answer
The answer is the maximum value of \(k\) among all \((k, b)\) where \(dp[k][b] < +\infty\) and \(b \leq B\).
Concrete Example
For example, with \(N=3, K=2, B=5\) and mountains (cost, altitude) = \((2, 100), (3, 200), (1, 150)\):
- Select mountain 1 → \(dp[1][2] = 100\)
- Select mountain 2 → \(dp[1][3] = 200\), and since \(dp[1][2]=100 < 200\), we get \(dp[2][5] = 200\)
- Select mountain 3 → \(dp[1][1] = 150\), and since \(dp[1][2]=100 < 150\), we get \(dp[2][3] = 150\)
Since \(k=2\) is achievable, the answer is \(2\).
Complexity
- Time complexity: \(O(N \times K \times B)\)
For each of the \(N\) mountains, we update a table of size \(K \times B\). At most \(500 \times 50 \times 500 = 12{,}500{,}000\) operations. - Space complexity: \(O(K \times B)\)
The size of the DP table. At most \(50 \times 500 = 25{,}000\).
Implementation Notes
Reverse-order loop: As with the 0-1 knapsack problem, to ensure each mountain peak is used at most once, loop \(k\) and \(b\) from large to small.
Sentinel value: Use \(-1\) (or a value corresponding to \(-\infty\)) as the initial value of \(dp[0][0]\), making it smaller than any mountain’s altitude (\(\geq 1\)), so the transition for selecting the first mountain works naturally.
Optimization of the upper bound of \(k\): By setting the loop upper bound of \(k\) to \(\min(K, i+1)\), we avoid unnecessary computation of selecting more than \(i+1\) mountains when only \(i+1\) mountains have been considered so far.
Source Code
import sys
def main():
input_data = sys.stdin.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
K = int(input_data[idx]); idx += 1
B = int(input_data[idx]); idx += 1
C = []
S = []
for i in range(N):
c = int(input_data[idx]); idx += 1
s = int(input_data[idx]); idx += 1
C.append(c)
S.append(s)
# dp[k][b] = minimum cost to select exactly k mountains with budget constraint,
# where the last mountain's elevation is tracked.
# Actually, let's think differently.
# dp[k][b] = the minimum possible last elevation when we have selected exactly k mountains
# using exactly cost b. But that's N*K*B states which is 500*50*500 = 12.5M, manageable.
# Better approach: dp[k][b] = minimum last elevation achievable by selecting exactly k mountains
# from the first i mountains considered so far, with total cost exactly b.
# We iterate over mountains and update.
# Actually, let's define:
# dp[k][b] = minimum last elevation when selecting exactly k mountains with total cost b
# Initialize dp[0][0] = -infinity (no mountain selected, any elevation is fine)
# For each mountain i with cost C[i] and elevation S[i]:
# For k from K down to 1:
# For b from B down to C[i]:
# if dp[k-1][b-C[i]] < S[i]:
# dp[k][b] = min(dp[k][b], S[i])
# Answer = max k such that any dp[k][b] for b <= B is finite.
INF = float('inf')
# dp[k][b] = minimum last elevation for exactly k selections with exactly cost b
# We want to minimize last elevation to allow more future selections
dp = [[INF] * (B + 1) for _ in range(K + 1)]
dp[0][0] = -1 # sentinel: no mountain selected, last elevation is -infinity
for i in range(N):
ci = C[i]
si = S[i]
# Iterate in reverse to avoid using mountain i twice
for k in range(min(K, i + 1), 0, -1):
for b in range(B, ci - 1, -1):
prev = dp[k - 1][b - ci]
if prev < si: # strict increase
if si < dp[k][b]:
dp[k][b] = si
ans = 0
for k in range(K + 1):
for b in range(B + 1):
if dp[k][b] < INF:
ans = max(ans, k)
print(ans)
main()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: