#include #include #include #include #include #include #include #include #include #include #include using namespace std; struct City { int x, y; long long w; }; struct Flight { int u, v; // 0-indexed cities int s, t; // minutes from 00:00 }; struct PlanePlan { int spoke; // 0-indexed city, must be != hub int phaseSlot; // 0..11 => 0..55 minutes offset from 06:00 bool startHub; }; struct EvalScore { unsigned __int128 win = 0; // primary objective (exact score proxy) __int128 margin = 0; // secondary objective (plateau breaker) }; static constexpr int DAY_START = 6 * 60; // 06:00 static constexpr int DAY_END = 21 * 60; // 21:00 static constexpr int Q = 21; // 11:00..21:00 every 30 min static constexpr int INF_NEG = -1'000'000'000; bool better_eval(const EvalScore& a, const EvalScore& b) { if (a.win != b.win) return a.win > b.win; return a.margin > b.margin; } int margin_step_from_latest(int sq, int ci) { // Clamp to +/-30 min in 5-min units to avoid INF dominating. constexpr int LIM = 6; if (sq <= INF_NEG / 2 && ci <= INF_NEG / 2) return 0; if (sq <= INF_NEG / 2) return +LIM; if (ci <= INF_NEG / 2) return -LIM; int step = (ci - sq) / 5; // times are multiples of 5 if (step > LIM) step = LIM; if (step < -LIM) step = -LIM; return step; } int parse_time_token(const string& tok) { auto pos = tok.find(':'); if (pos == string::npos) return stoi(tok); // fallback int hh = stoi(tok.substr(0, pos)); int mm = stoi(tok.substr(pos + 1)); return hh * 60 + mm; } void print_time(int minute) { int hh = minute / 60; int mm = minute % 60; cout << setw(2) << setfill('0') << hh << ':' << setw(2) << setfill('0') << mm; cout << setfill(' '); } int calc_duration_minutes(const City& c1, const City& c2) { // Need exact 5-minute ceil of (3 * distance / 40 + 40). long long dx = (long long)c1.x - (long long)c2.x; long long dy = (long long)c1.y - (long long)c2.y; long long d2 = dx * dx + dy * dy; // Max possible distance <= 2000 => duration <= 190. for (int dur = 40; dur <= 300; dur += 5) { long long lhs = 40LL * dur - 1600LL; // >= 0 if (lhs * lhs >= 9LL * d2) return dur; } return 300; // unreachable under constraints } struct Solver { int N = 0, R = 0; int M = 0, K = 0; vector cities; vector squareFlights; vector> dur; vector> eligible; vector> pairW; unsigned __int128 denomWeight = 0; // all eligible OD weights * Q array targetTimes{}; vector sqLatest; // [q][dst][src] flattened vector hubOrder; vector> spokeOrder; // per hub, sorted candidates chrono::steady_clock::time_point t0; double internalTimeLimitSec = 0.84; // keep margin for 1.0s TL int idx3(int q, int dst, int src) const { return (q * N + dst) * N + src; } bool time_over() const { double elapsed = chrono::duration(chrono::steady_clock::now() - t0).count(); return elapsed >= internalTimeLimitSec; } void read_input() { cin >> N >> R; cities.resize(N); for (int i = 0; i < N; ++i) { cin >> cities[i].x >> cities[i].y >> cities[i].w; } cin >> M; squareFlights.reserve(M); for (int i = 0; i < M; ++i) { int a, b; string sTok, tTok; cin >> a >> sTok >> b >> tTok; int s = parse_time_token(sTok); int t = parse_time_token(tTok); squareFlights.push_back(Flight{a - 1, b - 1, s, t}); } cin >> K; for (int q = 0; q < Q; ++q) targetTimes[q] = 11 * 60 + 30 * q; } void precompute_geometry() { dur.assign(N, vector(N, 0)); eligible.assign(N, vector(N, 0)); pairW.assign(N, vector(N, 0)); for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { if (i != j) dur[i][j] = calc_duration_minutes(cities[i], cities[j]); long long dx = (long long)cities[i].x - (long long)cities[j].x; long long dy = (long long)cities[i].y - (long long)cities[j].y; long long d2 = dx * dx + dy * dy; // distance >= 0.25R <=> 16*d^2 >= R^2 if (16LL * d2 >= 1LL * R * R) { eligible[i][j] = 1; pairW[i][j] = (unsigned long long)cities[i].w * (unsigned long long)cities[j].w; } } } unsigned __int128 oneQuery = 0; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { if (eligible[i][j]) oneQuery += (unsigned __int128)pairW[i][j]; } } denomWeight = oneQuery * (unsigned __int128)Q; } void precompute_orders() { vector> hubs; hubs.reserve(N); spokeOrder.assign(N, {}); for (int h = 0; h < N; ++h) { long double acc = 0.0L; vector> cand; cand.reserve(max(0, N - 1)); for (int v = 0; v < N; ++v) { if (v == h) continue; long double s = (long double)cities[v].w / (long double)dur[h][v]; cand.push_back({s, v}); acc += s; } sort(cand.begin(), cand.end(), [&](const auto& a, const auto& b) { if (a.first != b.first) return a.first > b.first; return a.second < b.second; }); spokeOrder[h].reserve(cand.size()); for (auto& p : cand) spokeOrder[h].push_back(p.second); long double hubScore = acc * (long double)cities[h].w; hubs.push_back({hubScore, h}); } sort(hubs.begin(), hubs.end(), [&](const auto& a, const auto& b) { if (a.first != b.first) return a.first > b.first; return a.second < b.second; }); hubOrder.clear(); hubOrder.reserve(N); for (auto& p : hubs) hubOrder.push_back(p.second); } void precompute_square_latest() { vector fs = squareFlights; sort(fs.begin(), fs.end(), [&](const Flight& a, const Flight& b) { if (a.s != b.s) return a.s > b.s; if (a.t != b.t) return a.t > b.t; if (a.u != b.u) return a.u < b.u; return a.v < b.v; }); sqLatest.assign(Q * N * N, INF_NEG); vector best(N); for (int q = 0; q < Q; ++q) { int T = targetTimes[q]; for (int dst = 0; dst < N; ++dst) { fill(best.begin(), best.end(), INF_NEG); best[dst] = T; for (const auto& f : fs) { if (best[f.v] >= f.t && best[f.u] < f.s) { best[f.u] = f.s; } } for (int src = 0; src < N; ++src) { sqLatest[idx3(q, dst, src)] = best[src]; } } } } vector build_circle_flights(int hub, const vector& plans) const { vector flights; flights.reserve(K * 16); for (int p = 0; p < K; ++p) { int spoke = plans[p].spoke; if (spoke == hub) continue; // safety fallback int cur = plans[p].startHub ? hub : spoke; int tm = DAY_START + 5 * plans[p].phaseSlot; while (true) { int nxt = (cur == hub ? spoke : hub); int arr = tm + dur[cur][nxt]; if (arr > DAY_END) break; flights.push_back(Flight{cur, nxt, tm, arr}); cur = nxt; tm = arr; } } sort(flights.begin(), flights.end(), [&](const Flight& a, const Flight& b) { if (a.s != b.s) return a.s > b.s; if (a.t != b.t) return a.t > b.t; if (a.u != b.u) return a.u < b.u; return a.v < b.v; }); return flights; } EvalScore evaluate_score(int hub, const vector& plans) const { vector flights = build_circle_flights(hub, plans); vector best(N); EvalScore score; for (int q = 0; q < Q; ++q) { int T = targetTimes[q]; for (int dst = 0; dst < N; ++dst) { fill(best.begin(), best.end(), INF_NEG); best[dst] = T; for (const auto& f : flights) { if (best[f.v] >= f.t && best[f.u] < f.s) { best[f.u] = f.s; } } int base = (q * N + dst) * N; for (int src = 0; src < N; ++src) { if (!eligible[src][dst]) continue; int sq = sqLatest[base + src]; int ci = best[src]; if (sq < ci) { score.win += (unsigned __int128)pairW[src][dst]; } int mstep = margin_step_from_latest(sq, ci); score.margin += (__int128)pairW[src][dst] * (__int128)mstep; } } } return score; } vector initial_plans_for_hub(int hub) const { vector plans(K); const auto& order = spokeOrder[hub]; int m = (int)order.size(); for (int p = 0; p < K; ++p) { plans[p].spoke = order[p % m]; plans[p].phaseSlot = p % 12; plans[p].startHub = (p % 2 == 0); } return plans; } struct SearchResult { int hub = 0; vector plans; EvalScore score; }; SearchResult optimize_one_hub(int hub) { static constexpr int MAX_PASSES = 2; static constexpr int SPOKE_CAND_LIMIT = 20; static constexpr int PHASE_SWAP_CAND_LIMIT = 8; SearchResult res; res.hub = hub; res.plans = initial_plans_for_hub(hub); res.score = evaluate_score(hub, res.plans); bool any = true; for (int pass = 0; pass < MAX_PASSES && any && !time_over(); ++pass) { any = false; for (int p = 0; p < K; ++p) { if (time_over()) break; // 1) Spoke coordinate { int curSpoke = res.plans[p].spoke; int bestSpoke = curSpoke; EvalScore bestVal = res.score; int tried = 0; for (int cand : spokeOrder[hub]) { if (cand == hub || cand == curSpoke) continue; res.plans[p].spoke = cand; EvalScore val = evaluate_score(hub, res.plans); if (better_eval(val, bestVal)) { bestVal = val; bestSpoke = cand; } ++tried; if (tried >= SPOKE_CAND_LIMIT) break; if ((tried & 3) == 0 && time_over()) break; } res.plans[p].spoke = bestSpoke; if (better_eval(bestVal, res.score)) { res.score = bestVal; any = true; } } if (time_over()) break; // 2) Phase coordinate (0..11 => 0..55 minutes) { int curPhase = res.plans[p].phaseSlot; int bestPhase = curPhase; EvalScore bestVal = res.score; for (int ph = 0; ph < 12; ++ph) { if (ph == curPhase) continue; res.plans[p].phaseSlot = ph; EvalScore val = evaluate_score(hub, res.plans); if (better_eval(val, bestVal)) { bestVal = val; bestPhase = ph; } if ((ph & 3) == 3 && time_over()) break; } res.plans[p].phaseSlot = bestPhase; if (better_eval(bestVal, res.score)) { res.score = bestVal; any = true; } } if (time_over()) break; // 3) Phase swap with another plane (pair move) { int bestQ = -1; EvalScore bestVal = res.score; int tried = 0; for (int q2 = p + 1; q2 < K; ++q2) { if (res.plans[q2].phaseSlot == res.plans[p].phaseSlot) continue; swap(res.plans[p].phaseSlot, res.plans[q2].phaseSlot); EvalScore val = evaluate_score(hub, res.plans); if (better_eval(val, bestVal)) { bestVal = val; bestQ = q2; } swap(res.plans[p].phaseSlot, res.plans[q2].phaseSlot); ++tried; if (tried >= PHASE_SWAP_CAND_LIMIT) break; if ((tried & 3) == 0 && time_over()) break; } if (!time_over() && tried < PHASE_SWAP_CAND_LIMIT) { for (int q2 = 0; q2 < p; ++q2) { if (res.plans[q2].phaseSlot == res.plans[p].phaseSlot) continue; swap(res.plans[p].phaseSlot, res.plans[q2].phaseSlot); EvalScore val = evaluate_score(hub, res.plans); if (better_eval(val, bestVal)) { bestVal = val; bestQ = q2; } swap(res.plans[p].phaseSlot, res.plans[q2].phaseSlot); ++tried; if (tried >= PHASE_SWAP_CAND_LIMIT) break; if ((tried & 3) == 0 && time_over()) break; } } if (bestQ != -1) { swap(res.plans[p].phaseSlot, res.plans[bestQ].phaseSlot); res.score = bestVal; any = true; } } if (time_over()) break; // 4) Start direction coordinate { bool curDir = res.plans[p].startHub; bool bestDir = curDir; EvalScore bestVal = res.score; res.plans[p].startHub = !curDir; EvalScore val = evaluate_score(hub, res.plans); if (better_eval(val, bestVal)) { bestVal = val; bestDir = !curDir; } res.plans[p].startHub = bestDir; if (better_eval(bestVal, res.score)) { res.score = bestVal; any = true; } } } } return res; } SearchResult solve() { t0 = chrono::steady_clock::now(); read_input(); precompute_geometry(); precompute_orders(); precompute_square_latest(); SearchResult bestAll; bool initialized = false; int hubTrials = min(N, 4); for (int i = 0; i < hubTrials; ++i) { if (time_over()) break; int hub = hubOrder[i]; SearchResult cand = optimize_one_hub(hub); if (!initialized || better_eval(cand.score, bestAll.score)) { bestAll = std::move(cand); initialized = true; } } if (!initialized) { int hub = hubOrder.empty() ? 0 : hubOrder[0]; bestAll = optimize_one_hub(hub); } return bestAll; } void output_answer(const SearchResult& ans) const { // Rebuild grouped by plane for output in required format. vector> perPlane(K); for (int p = 0; p < K; ++p) { int spoke = ans.plans[p].spoke; if (spoke == ans.hub) continue; int cur = ans.plans[p].startHub ? ans.hub : spoke; int tm = DAY_START + 5 * ans.plans[p].phaseSlot; while (true) { int nxt = (cur == ans.hub ? spoke : ans.hub); int arr = tm + dur[cur][nxt]; if (arr > DAY_END) break; perPlane[p].push_back(Flight{cur, nxt, tm, arr}); cur = nxt; tm = arr; } } for (int p = 0; p < K; ++p) { cout << perPlane[p].size() << '\n'; for (const auto& f : perPlane[p]) { cout << (f.u + 1) << ' '; print_time(f.s); cout << ' ' << (f.v + 1) << ' '; print_time(f.t); cout << '\n'; } } } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); Solver solver; auto ans = solver.solve(); solver.output_answer(ans); return 0; }