D - お買い物上手 / Smart Shopper 解説 by admin
Claude 4.6 Opus (Thinking)Overview
Given \(N\) items, select any combination such that the total cost is maximized while staying within a budget of \(K\) yen. This is a classic 0-1 knapsack problem (subset sum problem).
Analysis
Naive Approach
For each of the \(N\) items, there are 2 choices: “buy” or “don’t buy,” giving \(2^N\) total combinations. When \(N\) can be up to \(100\), \(2^{100}\) is an astronomically large number, making brute-force search completely infeasible (TLE).
Key Insight
In this problem, only “is the total cost at most \(K\)?” matters, and \(K \leq 10^4\) is relatively small. Therefore, we can use dynamic programming (DP) that tracks “can we achieve exactly \(j\) yen as the total cost?” for each \(j = 0, 1, 2, \ldots, K\).
Concrete Example
For example, with \(N = 3\), \(K = 10\), \(C = [3, 5, 7]\): - Buy nothing → total \(0\) yen ✓ - \(\{3\}\) → \(3\) yen ✓ - \(\{5\}\) → \(5\) yen ✓ - \(\{3, 5\}\) → \(8\) yen ✓ - \(\{7\}\) → \(7\) yen ✓ - \(\{3, 7\}\) → \(10\) yen ✓ ← This is the maximum - \(\{5, 7\}\) → \(12\) yen ✗ (exceeds \(K\))
Using DP, we can efficiently determine all of these.
Algorithm
We use a 0-1 knapsack-style subset sum DP.
- DP array definition:
dp[j]= “Can we select some items to make the total cost exactly \(j\) yen? (True/False)” - Initial state:
dp[0] = True(buying nothing gives a total of \(0\) yen); all others areFalse - Transition: For each item with cost \(c\), iterate in reverse order \(j = K, K-1, \ldots, c\), and if
dp[j - c]isTrue, setdp[j] = True- Reason for iterating in reverse: To prevent using the same item more than once. If we iterate forward, the effect of a single item propagates multiple times.
- Obtaining the answer: Check \(j = K, K-1, \ldots, 0\) in order, and the first \(j\) where
dp[j]isTrueis the answer.
Complexity
- Time complexity: \(O(N \times K)\)
- For each of the \(N\) items, we scan all costs up to \(K\)
- At most about \(100 \times 10^4 = 10^6\), which is sufficiently fast
- Space complexity: \(O(K)\)
- Only a 1-dimensional DP array is used
Implementation Notes
Reverse-order loop is crucial: By looping in descending order from \(K\) down to \(c\) with
for j in range(K, c - 1, -1), we guarantee that each item is selected at most once. If we loop in ascending order (range(c, K+1)), the same item could be used multiple times (turning it into a subset sum problem with repetition), so care must be taken.The update rule is simply: if
dp[j - c]isTrue, setdp[j] = True.Finally, by finding the largest \(j\) where
dp[j]isTrue, we obtain the maximum total cost that does not exceed \(K\).Source Code
N, K = map(int, input().split())
C = list(map(int, input().split()))
dp = [False] * (K + 1)
dp[0] = True
for c in C:
for j in range(K, c - 1, -1):
if dp[j - c]:
dp[j] = True
for j in range(K, -1, -1):
if dp[j]:
print(j)
break
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: