Submission #1295306

#TimeUsernameProblemLanguageResultExecution timeMemory
1295306duongquanghai08Sailing Race (CEOI12_race)C++20
0 / 100
1673 ms16572 KiB
#include <iostream> #include <vector> #include <algorithm> #include <cstring> using namespace std; const int MAXN = 1005; // 2 * N const int INF = 1e9; int N, K; vector<int> adj[MAXN]; int dp[MAXN][MAXN][2]; // dp[i][j][0]: max path in range [i, j] starting at i // dp[i][j][1]: max path in range [i, j] starting at j // For K=1 specific calculation int memo_bonus[MAXN][MAXN][2]; int visited_bonus[MAXN][MAXN][2]; int bonus_token = 0; int W[MAXN]; // W[u] stores max extension from u crossing to the other side // Function to find max path in [L, R] starting at 'side' (0 for L, 1 for R) // that ends at some node u and adds W[u]. int solve_bonus(int L, int R, int side) { if (L == R) return W[L] > -INF ? W[L] : -INF; if (visited_bonus[L][R][side] == bonus_token) return memo_bonus[L][R][side]; int res = -INF; int u = (side == 0) ? L : R; // Option 1: Stop here if (W[u] > -INF) res = max(res, W[u]); // Option 2: Continue path for (int v : adj[u]) { if (v > L && v < R) { // Strict interior of [L, R] // Edge u -> v. // Split into [L, v] and [v, R]. // If we go L -> v (side 0), we are at v. v is R of [L, v] and L of [v, R]. // We can recurse into [L, v] (start at R) or [v, R] (start at L). int val_left = solve_bonus(L, v, 1); // inside [L, v], start v int val_right = solve_bonus(v, R, 0); // inside [v, R], start v int best_next = max(val_left, val_right); if (best_next > -INF) { res = max(res, 1 + best_next); } } } visited_bonus[L][R][side] = bonus_token; memo_bonus[L][R][side] = res; return res; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); if (!(cin >> N >> K)) return 0; for (int i = 0; i < N; ++i) { int v; while (cin >> v && v != 0) { v--; // 0-based // Add edges in doubled space to handle modular arithmetic easily // u -> v implies u -> v and u+N -> v+N (and potentially u -> v+N if v < u) // We normalize so v is in [u+1, u+N-1] // For u in [0, N-1] int target = v; if (target <= i) target += N; adj[i].push_back(target); adj[i + N].push_back(target + N); } } // Initialize DP for (int i = 0; i < 2 * N; ++i) { for (int j = 0; j < 2 * N; ++j) { dp[i][j][0] = dp[i][j][1] = -INF; } dp[i][i][0] = dp[i][i][1] = 0; } // Compute standard DP (K=0 logic) for (int len = 1; len < N; ++len) { for (int i = 0; i < 2 * N; ++i) { int j = i + len; if (j >= 2 * N) break; // dp[i][j][0]: start at i for (int k : adj[i]) { if (k > i && k <= j) { int val = 1 + max(dp[i][k][1], dp[k][j][0]); dp[i][j][0] = max(dp[i][j][0], val); } } // dp[i][j][1]: start at j // We need reverse edges for this, or just check 'k' neighbors // Since graph is directed, we check outgoing from j? // NO. The path starts at j. So we look for neighbors of j. // But problem input is "direct destinations FROM harbor". // So if path starts at j, we look at adj[j]. for (int k : adj[j]) { if (k >= i && k < j) { int val = 1 + max(dp[i][k][1], dp[k][j][0]); dp[i][j][1] = max(dp[i][j][1], val); } } } } int max_stages = 0; int start_harbor = 1; // Check K=0 solutions and base for K=1 // A path is defined by the first edge u -> v. // Length = 1 + max path from v inside [v, u+N] for (int u = 0; u < N; ++u) { for (int v : adj[u]) { if (v > u && v < u + N) { // Path starts u -> v. Next part in [v, u+N]. // We are at v. We can go L (towards v) or R (towards u+N)? // In [v, u+N], v is the left boundary. // So we need path starting at v inside [v, u+N]. // This is dp[v][u+N][0]. // Also need to check if we treat v as right boundary of [u, v]? // No, the remaining circle is [v, u+N]. int val = dp[v][u + N][0]; if (val > -INF) { if (1 + val > max_stages) { max_stages = 1 + val; start_harbor = u + 1; } } else { // Just the edge u->v if (1 > max_stages) { max_stages = 1; start_harbor = u + 1; } } } } } if (K == 1) { // Iterate all possible first edges S->T for (int i = 0; i < N; ++i) { // S = i for (int k : adj[i]) { // T = k if (k > i && k < i + N) { // Region 1 (Left): [i, k] // Region 2 (Right): [k, i + N] // 1. Calculate W[u] for all u inside (i, k) // W[u] = max over crossing edges u->v (v in Region 2) of (1 + PathFrom(v)) // PathFrom(v) in Region 2 is max(dp[k][v][1], dp[v][i+N][0]) // We only need to compute W for u in [i+1, k-1] vector<int> nodes_in_left; for (int u = i + 1; u < k; ++u) { W[u] = -INF; nodes_in_left.push_back(u); for (int v : adj[u]) { if (v > k && v < i + N) { // Crossing edge int path_from_v = -INF; // Option A: v goes towards k (Left in [k, v]) -> dp[k][v][1] // Option B: v goes towards i+N (Right in [v, i+N]) -> dp[v][i+N][0] path_from_v = max(dp[k][v][1], dp[v][i+N][0]); if (path_from_v > -INF) { W[u] = max(W[u], 1 + path_from_v); } else { W[u] = max(W[u], 1); // Edge exists but no further path } } } } // 2. Compute max path in [i, k] starting at k ending at some u with bonus W[u] // We use solve_bonus(i, k, 1) -> starts at k (Right side of [i, k]) bonus_token++; int bonus_path = solve_bonus(i, k, 1); if (bonus_path > -INF) { if (1 + bonus_path > max_stages) { max_stages = 1 + bonus_path; start_harbor = i + 1; } } } } } } cout << max_stages << endl; cout << start_harbor << endl; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...