C - 荷物運びの報酬 / Reward for Carrying Luggage 解説 by admin
GPT 5.4 HighOverview
This problem is solved using dynamic programming where the state is “how many packages you are currently carrying.”
By scanning the rooms from left to right and updating the maximum reward for each number of packages, we can find the maximum reward satisfying the conditions.
Analysis
At each room, you choose to “accept / decline” a job, but the only things relevant to the constraints are:
- How far you have looked so far
- How many packages you are currently carrying
These are the only two factors.
In other words, the detailed information about which jobs you selected in the past is unnecessary, and
it suffices to keep only “the current number of packages” as the state.
1. Naive exhaustive search is infeasible
Since there are 2 choices at each room, an exhaustive search would yield \(2^N\) possibilities.
With \(N \le 10^5\), this is obviously too slow.
2. Consider a state DP
Define the DP as follows:
- \(dp[j]\) := “Among all ways of choosing jobs from the rooms seen so far such that you are carrying \(j\) packages, the maximum reward obtainable”
In the initial state, you carry 0 packages, so:
- \(dp[0] = 0\)
- \(dp[j] = -\infty \ (j \ge 1)\)
What we ultimately need is “carrying 0 packages after processing all rooms,” so the answer is the final value of \(dp[0]\).
3. Consider the transitions
Loading job (\(T_i = 1\))
You earn reward \(A_i\), and the number of packages increases by 1.
- Decline: the number of packages stays the same
- Accept: \(j \to j+1\) (provided \(j+1 \le K\))
Therefore, the transitions are:
[ \text{newdp}[j] = \max(\text{newdp}[j], dp[j]) ] [ \text{newdp}[j+1] = \max(\text{newdp}[j+1], dp[j] + A_i) ]
Unloading job (\(T_i = 0\))
You earn reward \(A_i\), and:
- If you have 1 or more packages, the count decreases by 1
- If you have 0 packages, it stays at 0
That is, if you accept:
- If \(j \ge 1\), then \(j \to j-1\)
- If \(j = 0\), then \(0 \to 0\)
Therefore, in addition to:
[ \text{newdp}[j] = \max(\text{newdp}[j], dp[j]) \quad \text{(decline)} ]
- For \(j \ge 1\): \(dp[j] + A_i\) contributes to \(\text{newdp}[j-1]\)
- For \(j = 0\): \(dp[0] + A_i\) contributes to \(\text{newdp}[0]\)
4. “Unloading with 0 packages” is always beneficial
In this problem, \(A_i \ge 1\).
Therefore, accepting an “unloading job” when you have 0 packages does not change the number of packages and only increases the reward.
In other words, there is no reason to decline that job when you have 0 packages.
Thanks to this property, the transition for \(j=0\) during an unloading job can be written as:
[
\text{newdp}[0]
\max(dp[0] + A_i,\ dp[1] + A_i) ]
(The “decline” option gives \(dp[0]\), but since \(A_i > 0\), \(dp[0] + A_i\) is always better.)
5. Why a 1-dimensional DP suffices
Originally, including whether we have processed up to the \(i\)-th room as part of the state would make it a 2-dimensional DP. However, since updating each room only uses “the previous state,” the \(i\) dimension is unnecessary.
Therefore, it can be compressed into a 1-dimensional DP with a single array.
6. Naive in-place updates break correctness, so pay attention to update order
When updating in place with a 1-dimensional array, you need to be careful about the update order to avoid effectively using the same room’s job multiple times.
- Loading job: The transition goes \(j \to j+1\), so update from large \(j\) to small \(j\)
- Unloading job: The transition goes \(j+1 \to j\), so update from small \(j\) to large \(j\)
This ensures correct transitions where each room’s job is used at most once.
Algorithm
Use a DP array \(dp[0 \ldots K]\).
- Initialization:
- \(dp[0] = 0\)
- All others are \(-\infty\)
For each room \((T_i, A_i)\), do the following:
1. \(T_i = 1\) (Loading job)
The number of packages increases by 1, so update from the back.
[ dp[j+1] = \max(dp[j+1], dp[j] + A_i) \quad (j = K-1, K-2, \dots, 0) ]
For the “decline” case, simply leave \(dp[j]\) as is.
2. \(T_i = 0\) (Unloading job)
The number of packages decreases by 1 (stays at 0 if already 0), so update from the front.
First, since \(dp[0]\) can come from both the old \(dp[0]\) and \(dp[1]\), compute it beforehand:
[ best0 = \max(dp[0] + A_i,\ dp[1] + A_i) ]
Next, for \(j = 1\) to \(K-1\):
[ dp[j] = \max(dp[j], dp[j+1] + A_i) ]
Finally, set:
[ dp[0] = best0 ]
\(dp[K]\) can only remain from the “decline” case, so it stays as is.
After processing all rooms,
[ dp[0] ]
is the answer.
Complexity
- Time complexity: \(O(NK)\)
- Space complexity: \(O(K)\)
Since the constraints include \(NK \le 10^7\), this complexity is well within the time limit.
Implementation Notes
- Initialize unreachable states with a sufficiently small value (e.g.,
-10**30) - Loading jobs: update from back to front
- Unloading jobs: update from front to back
- For unloading jobs, save the value for
dp[0]into a separate variablebest0before overwritingdp[1]
By following these three points, you can safely implement the 1-dimensional DP in code.
Source Code
import sys
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
if not data:
return
it = iter(data)
N = next(it)
K = next(it)
NEG = -10**30
dp = [NEG] * (K + 1)
dp[0] = 0
for _ in range(N):
t = next(it)
a = next(it)
if t == 1:
for j in range(K - 1, -1, -1):
v = dp[j] + a
if v > dp[j + 1]:
dp[j + 1] = v
else:
best0 = dp[0] + a
v = dp[1] + a
if v > best0:
best0 = v
for j in range(1, K):
v = dp[j + 1] + a
if v > dp[j]:
dp[j] = v
dp[0] = best0
print(dp[0])
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.4-high.
投稿日時:
最終更新: