제출 #1295738

#제출 시각아이디문제언어결과실행 시간메모리
1295738duongquanghai08Sailing Race (CEOI12_race)C++20
100 / 100
806 ms5392 KiB
#include <bits/stdc++.h> using namespace std; #define fi first #define se second // edge[i][j] = 1 nếu có cung (i -> j) int edge[505][505]; // dp[l][r][x] : k = 0, đường đi tối đa từ l đến r, // trên cung theo hướng x (0 = chiều kim, 1 = ngược chiều) // dp1[l][r][x] : k <= 1, cho phép 1 giao cắt trên cung đó int dp[505][505][2]; int dp1[505][505][2]; // nx[i][0] = i+1 (mod n); nx[i][1] = i-1 (mod n) int nx[505][2]; int n, type; // giải cho đoạn (l -> r) theo hướng x void solve(int l, int r, int x) { // TH chọn cung trực tiếp (l -> r) if (edge[l][r]) { dp[l][r][x] = 1; // Sau đó tiếp tục đi từ r, sang phía còn lại (x^1), cho phép 1 giao cắt dp1[l][r][x] = 1 + dp1[r][nx[l][x]][x ^ 1]; } else { dp[l][r][x] = -n; dp1[l][r][x] = -n; } // Thử tách tại m: (l -> m) rồi (m -> r), không giao cắt (k = 0) for (int m = nx[l][x]; m != r; m = nx[m][x]) { dp[l][r][x] = max(dp[l][r][x], dp[l][m][x] + dp[m][r][x]); dp1[l][r][x] = max(dp1[l][r][x], dp[l][m][x] + dp1[m][r][x]); } // Cho phép 1 giao cắt ở đâu đó “đi vòng” qua nx[r][x^1] dp1[l][r][x] = max(dp1[l][r][x], dp1[l][nx[r][x ^ 1]][x]); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> type; for (int i = 0; i < n; i++) { int x; cin >> x; while (x != 0) { edge[i][x - 1] = 1; // input là 1-based cin >> x; } nx[i][0] = (i + 1) % n; // đi “xuôi” nx[i][1] = (i + n - 1) % n; // đi “ngược” } // DP theo độ dài d (cung ngắn hơn vòng tròn) for (int d = 1; d < n; d++) { for (int l = 0, r = (l + d) % n; l < n; l++, r = nx[r][0]) { solve(l, r, 0); solve(r, l, 1); } } // ans = {số cạnh tối đa, điểm bắt đầu 1-based} pair<int,int> ans = { -1, 0 }; // Trường hợp k = 0: chỉ dùng dp1 (đã include k = 0) trên mọi (l,r,x) for (int l = 0; l < n; l++) { for (int r = 0; r < n; r++) { for (int x = 0; x < 2; x++) { ans = max(ans, { dp1[l][r][x], l + 1 }); } } } // Nếu type = 1 thì cho phép thêm cấu hình có đúng 1 giao cắt “đặc biệt” if (type) { for (int l = 0; l < n; l++) { for (int r = 0; r < n; r++) { for (int x = 0; x < 2; x++) { if (dp[l][r][x] <= 0) continue; // không có đường k=0 từ l->r int st = nx[r][x]; // tìm st sao cho có cung (st -> l) cắt được (l->r) while (st != l && edge[st][l] == 0) st = nx[st][x]; if (st == l) continue; // không tìm được // ed chạy từ sau st tới trước l theo hướng x for (int ed = nx[st][x]; ed != l; ed = nx[ed][x]) { if (edge[r][ed]) { // cung (r -> ed) là cung cắt // chọn tốt nhất giữa 2 phía sau khi cắt int tail = max( dp1[ed][nx[l][x ^ 1]][x], dp1[ed][nx[st][x]][x ^ 1] ); // dp[l][r][x]: đoạn k=0 từ l tới r // +1 cho (st->l), +1 cho (r->ed), +tail cho phần còn lại ans = max( ans, make_pair(tail + 1 + 1 + dp[l][r][x], st + 1) ); } } } } } } cout << ans.fi << "\n" << ans.se; return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...