D - 都市巡回ラリー / City Tour Rally Editorial by admin
gemini-3.5-flash-highOverview
In this problem, given a base score that changes daily and a set of one-way travel routes, we need to plan a stay from Day 1 to Day \(K\) to maximize the total score obtained.
By using Dynamic Programming (DP), we can efficiently find the optimal solution within the time limit.
Analysis
1. State Definition
When considering the movement over \(K\) days, suppose we are staying in city \(v\) on day \(j\). In this case, the cities we can move to on the next day, \(j+1\), are only those to which a direct travel route exists from city \(v\). In addition, the formula for calculating the score obtained changes as the days progress.
Since the “current state (which city we are in on which day)” directly affects the next choices and the score obtained, we define the following Dynamic Programming (DP) table:
- \(dp[j][v]\): The maximum total score from Day 1 to Day \(j\) when staying in city \(v\) on Day \(j\) (or an invalid value such as \(-1\) if unreachable).
2. Transition Logic
To stay in city \(v\) on Day \(j\), on the previous day (Day \(j-1\)), we must have stayed in some city \(u\) from which there is a direct route to city \(v\).
Therefore, for all cities \(u\) that have a travel route to city \(v\) (i.e., there exists an edge \(u \to v\)), we find the maximum value of the total score up to the previous day, \(dp[j-1][u]\).
\[dp[j][v] = \max_{u \to v} (dp[j-1][u]) + \bigl((P_v \times j) \bmod Q\bigr)\]
However, if there is no city \(u\) where we could have stayed on the previous day (or if all \(dp[j-1][u]\) are the invalid value \(-1\)), we cannot stay in city \(v\) on Day \(j\), so \(dp[j][v] = -1\).
3. Space Complexity Optimization
If we straightforwardly prepare a 2D array of size \(K \times N\), the space complexity will be \(O(K \times N)\). However, the only information needed to calculate the states for Day \(j\) is the states of Day \(j-1\).
Therefore, by reusing two 1D arrays of size \(N\)—the DP table for the previous day (dp) and the DP table for the day currently being calculated (next_dp)—we can reduce the space complexity to \(O(N)\).
Algorithm
Constructing the Reverse Graph To efficiently find the cities \(u\) that can transition to city \(v\), we create an adjacency list
adj_revthat stores the given travel routes in the reverse direction.- When a route \(u \to v\) is given, we add \(u\) to
adj_rev[v].
- When a route \(u \to v\) is given, we add \(u\) to
Initialization (Day 1) On Day 1, we can start from any city.
- For all cities \(i\) (\(1 \leq i \leq N\)), we set \(dp[i] = (P_i \times 1) \bmod Q\).
DP Transitions (from Day 2 to Day \(K\)) For \(j = 2, 3, \ldots, K\), perform the following process:
- Initialize a new array
next_dpentirely with \(-1\). - For each city \(v\), examine all transition sources \(u\) contained in
adj_rev[v]. - Find the maximum value \(max\_prev\) among the valid transition sources (\(dp[u] \neq -1\)).
- If a valid transition source exists, set
next_dp[v] = max_prev + (P_v * j) % Q. - Update
dpwithnext_dp.
- Initialize a new array
Outputting the Answer Output the maximum value in the final
dparray (the states on Day \(K\)).
Complexity
Time Complexity: \(O(K(N + M))\)
- For each day \(j\) (from \(2\) to \(K\)), we explore all cities \(v\) and their transition sources \(u\). The total number of transitions checked is equal to the total number of edges \(M\) in the reverse graph.
- Thus, the time required for transitions per day is \(O(N + M)\).
- Since we repeat this for \(K\) days, the overall time complexity is \(O(K(N + M))\).
- Under the constraints (\(N \leq 1000, M \leq 50000, K \leq 1000\)), the number of operations in the worst case is approximately \(5 \times 10^7\), which is well within the execution time limit.
Space Complexity: \(O(N + M)\)
- We use \(O(N + M)\) memory for the adjacency list storing the reverse graph.
- The DP tables only require holding two arrays of size \(N+1\), which takes \(O(N)\) space.
- The overall space complexity is \(O(N + M)\), which runs with very low memory consumption.
Key Implementation Details
Using a Reverse Graph: By constructing a reverse adjacency list
adj_revto directly reference “where we can come from to reach city \(v\)” instead of “where we can go from city \(u\)”, we can avoid redundant searches and make the transitions simple and fast.Propagation of Unreachable States: We represent initial values and states that cannot be transitioned to as
-1. By checking thatdp[u] != -1during transitions, we correctly exclude impossible travel plans (plans where the travel route is cut off midway).Optimization with
std::move: In C++, by writingdp = move(next_dp), we can update the array by just swapping pointers without copying the array elements, which further reduces execution time.Source Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, M, K;
long long Q;
if (!(cin >> N >> M >> K >> Q)) return 0;
vector<long long> P(N + 1);
for (int i = 1; i <= N; ++i) {
cin >> P[i];
}
vector<vector<int>> adj_rev(N + 1);
for (int i = 0; i < M; ++i) {
int u, v;
cin >> u >> v;
adj_rev[v].push_back(u);
}
vector<long long> dp(N + 1, -1);
for (int i = 1; i <= N; ++i) {
dp[i] = (P[i] * 1) % Q;
}
for (int j = 2; j <= K; ++j) {
vector<long long> next_dp(N + 1, -1);
for (int v = 1; v <= N; ++v) {
long long max_prev = -1;
for (int u : adj_rev[v]) {
if (dp[u] != -1) {
max_prev = max(max_prev, dp[u]);
}
}
if (max_prev != -1) {
next_dp[v] = max_prev + (P[v] * j) % Q;
}
}
dp = move(next_dp);
}
long long ans = -1;
for (int i = 1; i <= N; ++i) {
ans = max(ans, dp[i]);
}
cout << ans << "\n";
return 0;
}
This editorial was generated by gemini-3.5-flash-high.
posted:
last update: