C - 隣接ペナルティ付き選択 / Selection with Adjacent Penalty 解説 by admin
gemini-3-flash-previewOverview
This is a problem of selecting one or more jobs from \(N\) jobs and maximizing the profit, which is the total reward minus “the number of consecutively selected pairs \(\times K\)”.
Analysis
When deciding whether to “select” or “not select” each job \(i\), whether the penalty \(K\) is incurred depends on whether the previous job \(i-1\) was selected. Problems like this, where the previous state affects the current choice, can be efficiently solved using dynamic programming (DP).
Key Points
- State definition: When considering up to job \(i\), we need to maintain two states: “job \(i\) is selected” and “job \(i\) is not selected”.
- “Select at least one” constraint: Since all \(A_i\) are integers of at least 1, the final profit is guaranteed to be positive. By appropriately handling the initial state of “nothing selected yet” (initializing with a very small value \(-\infty\)), this constraint is naturally satisfied.
- Transition logic:
- If job \(i\) is not selected: Carry over the maximum profit so far, regardless of whether job \(i-1\) was selected or not.
- If job \(i\) is selected:
- Job \(i\) is the first job selected (profit: \(A_i\))
- Job \(i-1\) was not selected, and job \(i\) is selected (profit: \(dp[i-1][\text{not selected}] + A_i\))
- Job \(i-1\) was also selected, and job \(i\) is also selected (profit: \(dp[i-1][\text{selected}] + A_i - K\))
Algorithm
We perform DP with the following two states:
dp0: The maximum profit among jobs \(1 \dots i\) when job \(i\) is not selecteddp1: The maximum profit among jobs \(1 \dots i\) when job \(i\) is selected
Transition Equations
For each \(i = 1, \dots, N-1\), letting the values from the previous step be prev_dp0 and prev_dp1:
dp0 = max(prev_dp0, prev_dp1)- Since job \(i\) is not selected, no penalty is incurred. We simply take the maximum up to \(i-1\).
dp1 = max(A[i], prev_dp0 + A[i], prev_dp1 + A[i] - K)A[i]: Selecting job \(i\) as the very first jobprev_dp0 + A[i]: The previous job was not selected, and we select the current oneprev_dp1 + A[i] - K: The previous job was also selected, and we select the current one too (penalty \(K\) is incurred)
The answer is max(dp0, dp1) at the end.
Complexity
- Time complexity: \(O(N)\)
- We scan through \(N\) jobs once, performing constant-time computation at each step.
- Space complexity: \(O(N)\)
- \(O(N)\) is required to store the input array \(A\). The DP transition itself can be implemented with \(O(1)\) additional space (variables only).
Implementation Notes
Initial values: For the first job (\(i=0\)),
dp0is set to \(-\infty\) to indicate “nothing has been selected yet”, anddp1is set toA[0].Fast I/O: Since \(N\) can be as large as \(2 \times 10^5\), in Python, reading all input at once using
sys.stdin.read().split()can reduce execution time.Penalty handling: When \(m\) consecutive jobs are selected, the number of pairs is \(m-1\), so the transition
prev_dp1 + A[i] - Kcorrectly computes the penalty.Source Code
import sys
def solve():
# Fast I/O: read all input at once and split into tokens
# This is more efficient for large inputs in competitive programming.
input_data = sys.stdin.read().split()
if not input_data:
return
# N: number of jobs, K: penalty per continuous pair
N = int(input_data[0])
K = int(input_data[1])
# A: rewards for each job A_1, A_2, ..., A_N
# list(map(int, ...)) is efficient for converting tokens to integers.
A = list(map(int, input_data[2:]))
# dp0: Maximum profit considering jobs 1 to i, where job i is NOT selected.
# We use -inf to ensure that the "at least one job" requirement is handled.
# dp1: Maximum profit considering jobs 1 to i, where job i IS selected.
# Base case: the first job (index 0)
# Since A_i >= 1, the maximum profit will always be positive.
inf = 10**18
dp0 = -inf
dp1 = A[0]
# DP transitions for jobs i = 1 to N-1
for i in range(1, N):
# Store values from the previous step (job i-1)
prev_dp0 = dp0
prev_dp1 = dp1
# Transition for not selecting job i:
# We take the maximum profit achievable from the first i-1 jobs.
dp0 = max(prev_dp0, prev_dp1)
# Transition for selecting job i:
# There are three sub-cases for selecting job i:
# 1. Job i is the first job selected in the sequence.
# 2. Job i is selected, and some job(s) from the first i-1 were selected,
# but job i-1 was NOT selected.
# 3. Job i is selected, and job i-1 WAS selected (incurring a penalty K).
# Combining Case 1 and Case 2: A[i] + max(0, prev_dp0)
# Note: Since A_i >= 1, finite prev_dp0 is always >= 1.
dp1 = max(A[i], prev_dp0 + A[i], prev_dp1 + A[i] - K)
# The final answer is the maximum of the two states after considering all N jobs.
print(max(dp0, dp1))
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3-flash-preview.
投稿日時:
最終更新: