C - 食料の買い出し / Grocery Shopping 解説 by admin
Gemini 3.0 Flash (Thinking)Overview
This problem asks for the minimum cost required to cover at least \(D\) days’ worth of meals in total. Since each item (food pack) can be selected any number of times, this can be solved as a minimization version of the classic unbounded knapsack problem (complete knapsack problem).
Analysis
1. Nature of the Problem
Food packs sold at each store can be purchased any number of times. The goal is to “make the total number of days at least \(D\),” but importantly, it does not need to be exactly \(D\) days — exceeding \(D\) is perfectly fine.
2. Dynamic Programming (DP) Design
We consider an array dp[j] that manages “the minimum cost to cover \(j\) days’ worth of meals.”
In a standard knapsack problem, we aim for “exactly \(j\),” but since we want “at least \(D\) days” this time, we define it as follows:
dp[j](\(0 \leq j < D\)): the minimum cost to cover exactly \(j\) days’ worth of mealsdp[D]: the minimum cost to cover at least \(D\) days’ worth of meals
3. Key Optimization Points
- Eliminating redundant data: If multiple packs can cover the same number of days \(F_i\), it is sufficient to only consider the one with the lowest price \(C_i\).
- Upper bound on days: Since \(D\) days is sufficient, if a single pack covers \(F_i\) days where \(F_i\) exceeds \(D\), we can treat it as \(F_i = D\) without affecting the result.
- Transition optimization: When \(j + F_i\) exceeds \(D\), all such transitions are consolidated into updating
dp[D].
Algorithm
Similar to the unbounded knapsack problem, we update a 1-dimensional DP table.
Initialization:
dp[0] = 0- All other
dp[j]are initialized to a very large value (infinity:INF).
Update: For each store’s pack (or the cheapest pack for each day count) \((C_i, F_i)\), perform the following transitions:
- If \(j + F_i < D\):
dp[j + F_i] = min(dp[j + F_i], dp[j] + C_i) - If \(j + F_i \geq D\):
dp[D] = min(dp[D], dp[j] + C_i)
By performing this update starting from \(j = 0\) in increasing order, cases where the same pack is selected multiple times are automatically accounted for.
- If \(j + F_i < D\):
Complexity
- Time complexity: \(O(N + D^2)\)
- Preprocessing store information takes \(O(N)\).
- For the number of pack types (at most \(D\) types), scanning the DP table (of size \(D\)) results in \(O(D^2)\) in the worst case.
- Since the constraints are \(N, D \leq 3000\), this runs sufficiently fast.
- Space complexity: \(O(D)\)
- Memory is needed to maintain a DP table of length \(D+1\).
Implementation Notes
Deduplication of packs: In case there are many packs with the same number of days, using a dictionary or array to precompute the minimum cost for each day count reduces the number of iterations in the main DP loop.
Update order: In the unbounded knapsack problem, to allow the same item to be selected multiple times, we loop over index \(j\) in increasing order for updates.
Handling days exceeding \(D\): The key to solving this problem is to not forget to consolidate transitions where
j + f >= Dintodp[D].Source Code
import sys
def solve():
# Fast I/O to read all input at once
input_data = sys.stdin.read().split()
if not input_data:
return
# Read N (number of shops) and D (number of days to cover)
N = int(input_data[0])
D = int(input_data[1])
# Pre-process shops to keep only the cheapest price for each duration.
# Any duration f > D is capped at D because we only need to cover at least D days.
min_costs = {}
idx = 2
for _ in range(N):
c = int(input_data[idx])
f = int(input_data[idx+1])
idx += 2
if f > D:
f = D
if f not in min_costs or c < min_costs[f]:
min_costs[f] = c
# dp[j] stores the minimum cost to cover exactly j days for j < D.
# dp[D] stores the minimum cost to cover at least D days.
# Using a large integer for infinity.
INF = 10**18
dp = [INF] * (D + 1)
dp[0] = 0
# Convert min_costs to a list of (duration, cost) tuples
shops = list(min_costs.items())
for f, c in shops:
# Standard unbounded knapsack optimization:
# Update minimum cost for exactly j days where j < D.
# The forward loop allows us to use the same shop multiple times.
for j in range(D - f):
if dp[j] < INF:
new_v = dp[j] + c
if new_v < dp[j + f]:
dp[j + f] = new_v
# Update minimum cost for at least D days.
# This state is reached by adding one more pack of duration f to any
# existing plan covering j days such that j + f >= D.
# Since durations are capped at D, D - f will always be >= 0.
for j in range(D - f, D):
if dp[j] < INF:
new_v = dp[j] + c
if new_v < dp[D]:
dp[D] = new_v
# The answer is the minimum cost to cover at least D days.
print(dp[D])
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3-flash-thinking.
投稿日時:
最終更新: