D - アルバイトの計画 / Part-Time Job Planning Editorial by admin
Gemini 3.8 Flash (High)Overview
This problem asks us to maximize the total salary earned by choosing at most \(K\) days out of \(N\) days, subject to the constraint that any two chosen days must be separated by at least \(D+1\) days (meaning at least \(D\) rest days between them). We can solve this efficiently using dynamic programming (DP) and maintaining a running maximum (two-pointer approach).
Analysis
1. Problem Restatement
If day \(p\) is a working day and day \(q\) is the next working day, the problem conditions require the following: - \(q \ge p + D + 1\) (because after working on day \(p\), a rest period of \(D\) days is required) - The total number of chosen days must be between \(1\) and \(K\) inclusive (since \(A_i \ge 1\), it is always optimal to work at least \(1\) day if possible)
2. Naive Approach and Its Limitations
Consider a dynamic programming approach where the state is “the maximum salary when working for \(j\) days in total, with the last working day being day \(i\).” Denoting this state as \(\text{dp}[j][i]\), the transition from the previous working day \(p\) is as follows:
\[ \text{dp}[j][i] = \max_{1 \le p \le i - D - 1} (\text{dp}[j-1][p]) + A_i \]
If we compute this transition naively: - Number of days worked \(j\): \(1 \le j \le K\) (\(O(K)\) states) - Last working day \(i\): \(1 \le i \le N\) (\(O(N)\) states) - Previous working day \(p\): \(1 \le p \le i - D - 1\) (\(O(N)\) candidates)
In total, this takes \(O(K \times N^2)\) time. Since \(N, K \le 5000\), the number of operations can be up to \(5000^3 \approx 1.25 \times 10^{11}\), which exceeds the time limit and results in TLE (Time Limit Exceeded).
3. Optimization
As \(i\) increases from \(1\) to \(N\), the upper bound of the valid range of transitions \(p\), which is \(i - D - 1\), also increases monotonically. Therefore, we do not need to iterate over \(p\) from \(1\) each time to find the maximum. Instead, by maintaining the maximum value of \(\text{dp}[j-1][p]\) seen so far while advancing a pointer, we can retrieve the maximum value for each \(i\) in \(O(1)\) time.
This allows us to perform the computation for each \(j\) in \(O(N)\) time, reducing the overall time complexity to \(O(NK)\).
Algorithm
- Initialization:
- For \(j = 1\) (working for only 1 day), the salary earned by working on day \(i\) is \(A_i\).
- Set
prev_dp[i] = A[i], and initialize the maximum answeranswith these values as well.
- Updating the DP Table:
- Loop through the number of working days \(j\) from \(2\) to \(K\).
- Initialize a variable
max_val = -1to hold the maximum value up to the current point, and a pointerptr = 1to track the valid transition days. - While advancing the current day \(i\) from \(1\) to \(N\), perform the following:
- While
ptr <= i - D - 1, updatemax_val = max(max_val, prev_dp[ptr])and incrementptr. - If
max_val != -1(a valid transition source exists), setcurr_dp[i] = max_val + A[i]. - Update the answer with
ans = max(ans, curr_dp[i]).
- While
- If no updates occurred for any \(i\) (meaning it is impossible to work any more days under the constraints), break out of the loop early since checking further values of \(j\) is unnecessary.
- Replace
prev_dpwithcurr_dpand proceed to the next \(j\).
- Output:
- Print the final value of
ans.
- Print the final value of
Complexity
- Time Complexity: \(O(N \cdot K)\)
- The outer loop runs at most \(K\) times.
- In the inner loop, as \(i\) ranges from \(1\) to \(N\), the pointer
ptralso advances to at most \(N\). Therefore, each iteration of the outer loop takes \(O(N)\) time. - Thus, the overall time complexity is \(O(N \cdot K) \le 5000 \times 5000 = 2.5 \times 10^7\), which easily runs well within the standard time limit (usually 2 seconds).
- Space Complexity: \(O(N)\)
- By using a “rolling array” technique to store only the states for day \(j-1\) (
prev_dp) and day \(j\) (curr_dp), the memory requirement is kept to \(O(N)\).
- By using a “rolling array” technique to store only the states for day \(j-1\) (
Implementation Notes
Preventing Overflow: The maximum total salary can reach \(5000 \times 10^9 = 5 \times 10^{12}\), which exceeds the range of a 32-bit integer (
int). Make sure to use a 64-bit integer type (long longin C++) for the DP table and the answer variable.Handling Unreachable States: Represent states where it is impossible to work on that day for that number of days with a sentinel value such as
-1, ensuring that invalid transitions (transitions from unreachable states) do not occur.Source Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, k, d;
if (!(cin >> n >> k >> d)) return 0;
vector<long long> a(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
vector<long long> prev_dp(n + 1, -1);
long long ans = 0;
for (int i = 1; i <= n; ++i) {
prev_dp[i] = a[i];
ans = max(ans, prev_dp[i]);
}
vector<long long> curr_dp(n + 1, -1);
for (int j = 2; j <= k; ++j) {
long long max_val = -1;
int ptr = 1;
bool any_valid = false;
for (int i = 1; i <= n; ++i) {
curr_dp[i] = -1;
while (ptr <= i - d - 1) {
if (prev_dp[ptr] != -1) {
max_val = max(max_val, prev_dp[ptr]);
}
ptr++;
}
if (max_val != -1) {
curr_dp[i] = max_val + a[i];
ans = max(ans, curr_dp[i]);
any_valid = true;
}
}
if (!any_valid) {
break;
}
prev_dp = curr_dp;
}
cout << ans << "\n";
return 0;
}
This editorial was generated by gemini-3.8-flash-high.