#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using ll = long long; struct City { int x, y; ll w; }; struct Flight { int a, b; int s, t; }; struct PlanePlan { vector route; int offset = 0; int duration = 0; }; struct DemandTerm { int src, dst; long double w; array sq; }; constexpr int START_HOUR = 6; constexpr int END_HOUR = 21; constexpr int SLOT_MIN = 5; constexpr int MAX_SLOT = (END_HOUR - START_HOUR) * 60 / SLOT_MIN; // 180 constexpr int TARGET_CNT = 21; constexpr int TARGET_START = (11 - START_HOUR) * 60 / SLOT_MIN; // 60 constexpr int TARGET_STEP = 30 / SLOT_MIN; // 6 constexpr int NEG_INF = -1e9; int parseTimeToSlot(const string& s) { auto pos = s.find(':'); int hh = stoi(s.substr(0, pos)); int mm = stoi(s.substr(pos + 1)); return (hh * 60 + mm - START_HOUR * 60) / SLOT_MIN; } string slotToTime(int slot) { int total = START_HOUR * 60 + slot * SLOT_MIN; int hh = total / 60; int mm = total % 60; char buf[16]; snprintf(buf, sizeof(buf), "%02d:%02d", hh, mm); return string(buf); } int calcDurationSlot(const City& c1, const City& c2) { double dx = double(c1.x) - double(c2.x); double dy = double(c1.y) - double(c2.y); double d = sqrt(dx * dx + dy * dy); double minutes = 60.0 * d / 800.0 + 40.0; return (int)ceil(minutes / 5.0 - 1e-12); } int routeDuration(const vector& route, const vector>& dur) { int total = 0; for (int i = 1; i < (int)route.size(); ++i) { if (route[i - 1] == route[i]) return MAX_SLOT + 1; total += dur[route[i - 1]][route[i]]; if (total > MAX_SLOT) return total; } return total; } void normalizePlane(PlanePlan& p, const vector>& dur) { if (p.route.empty()) p.route.push_back(0); vector fixed; fixed.reserve(p.route.size()); fixed.push_back(p.route[0]); for (int i = 1; i < (int)p.route.size(); ++i) { if (p.route[i] != p.route[i - 1]) fixed.push_back(p.route[i]); } p.route.swap(fixed); if (p.route.empty()) p.route.push_back(0); p.duration = routeDuration(p.route, dur); while (p.duration > MAX_SLOT && (int)p.route.size() > 1) { p.route.pop_back(); p.duration = routeDuration(p.route, dur); } int lim = max(0, MAX_SLOT - p.duration); p.offset = min(max(0, p.offset), lim); } void appendPlaneFlights(const PlanePlan& p, const vector>& dur, vector& out) { int tm = p.offset; for (int i = 1; i < (int)p.route.size(); ++i) { int a = p.route[i - 1]; int b = p.route[i]; int nt = tm + dur[a][b]; out.push_back({a, b, tm, nt}); tm = nt; } } vector flattenPlans(const vector& plans, const vector>& dur) { vector flights; for (const auto& p : plans) appendPlaneFlights(p, dur, flights); return flights; } struct ScoreEvaluator { int N; uint64_t allMask; explicit ScoreEvaluator(int n) : N(n) { allMask = (N == 64 ? ~0ULL : ((1ULL << N) - 1)); } vector> buildByStart(const vector& flights, int target) const { vector> byStart(target + 1); for (const auto& f : flights) { if (f.s < 0 || f.s > target || f.t < 0 || f.t > target) continue; byStart[f.s].push_back(f); } return byStart; } vector> latestMatrixForTarget(const vector>& byStart, int target) const { vector> reach(target + 1, vector(N, 0ULL)); for (int c = 0; c < N; ++c) reach[target][c] = (1ULL << c); for (int tm = target - 1; tm >= 0; --tm) { for (int c = 0; c < N; ++c) reach[tm][c] = reach[tm + 1][c]; for (const auto& f : byStart[tm]) { reach[tm][f.a] |= reach[f.t][f.b]; } } vector> latest(N, vector(N, NEG_INF)); for (int src = 0; src < N; ++src) { uint64_t rem = allMask; for (int tm = target; tm >= 0 && rem; --tm) { uint64_t m = reach[tm][src] & rem; while (m) { int dst = __builtin_ctzll(m); latest[src][dst] = tm; rem &= ~(1ULL << dst); m &= (m - 1); } } } return latest; } vector>> precomputeSqBest(const vector& sqFlights) const { vector>> sqBest(TARGET_CNT, vector>(N, vector(N, NEG_INF))); for (int k = 0; k < TARGET_CNT; ++k) { int target = TARGET_START + TARGET_STEP * k; auto byStart = buildByStart(sqFlights, target); sqBest[k] = latestMatrixForTarget(byStart, target); } return sqBest; } double score( const vector& ciFlights, const vector& demands ) const { long double vSq = 0.0L, vCi = 0.0L; for (int k = 0; k < TARGET_CNT; ++k) { int target = TARGET_START + TARGET_STEP * k; auto byStart = buildByStart(ciFlights, target); auto latest = latestMatrixForTarget(byStart, target); for (const auto& d : demands) { if (d.sq[k] < latest[d.src][d.dst]) vCi += d.w; else vSq += d.w; } } long double den = vSq + vCi; if (den <= 0.0L) return 0.0; return (double)(vCi / den); } }; PlanePlan buildCyclicPlan( const vector& cycle, int offset, const vector>& dur ) { PlanePlan p; if (cycle.empty()) return p; p.route.push_back(cycle[0]); p.offset = offset; int tm = offset; int cur = cycle[0]; int idx = 1 % (int)cycle.size(); while (true) { int nxt = cycle[idx]; if (nxt == cur) break; int nt = tm + dur[cur][nxt]; if (nt > MAX_SLOT) break; p.route.push_back(nxt); tm = nt; cur = nxt; idx = (idx + 1) % (int)cycle.size(); } p.duration = tm - offset; normalizePlane(p, dur); return p; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, R; cin >> N >> R; vector cities(N); for (int i = 0; i < N; ++i) cin >> cities[i].x >> cities[i].y >> cities[i].w; int M; cin >> M; vector sqFlights(M); for (int i = 0; i < M; ++i) { int a, b; string ss, tt; cin >> a >> ss >> b >> tt; --a; --b; sqFlights[i] = {a, b, parseTimeToSlot(ss), parseTimeToSlot(tt)}; } int K; cin >> K; vector> dur(N, vector(N, 0)); for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) if (i != j) dur[i][j] = calcDurationSlot(cities[i], cities[j]); } vector> pairWeight(N, vector(N, 0.0L)); double threshold = 0.25 * R; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { double dx = double(cities[i].x) - double(cities[j].x); double dy = double(cities[i].y) - double(cities[j].y); double d = sqrt(dx * dx + dy * dy); if (d + 1e-12 >= threshold) { pairWeight[i][j] = (long double)cities[i].w * (long double)cities[j].w; } } } ScoreEvaluator evaluator(N); auto sqBest = evaluator.precomputeSqBest(sqFlights); // [k][src][dst] vector demands; demands.reserve(N * N); for (int src = 0; src < N; ++src) { for (int dst = 0; dst < N; ++dst) { if (pairWeight[src][dst] == 0.0L) continue; DemandTerm d; d.src = src; d.dst = dst; d.w = pairWeight[src][dst]; for (int k = 0; k < TARGET_CNT; ++k) d.sq[k] = sqBest[k][src][dst]; demands.push_back(d); } } vector cityScore(N, 0.0L); for (int i = 0; i < N; ++i) { long double s = (long double)cities[i].w * 1e6L; for (int j = 0; j < N; ++j) s += pairWeight[i][j] + pairWeight[j][i]; cityScore[i] = max((long double)1.0, s); } vector cityOrd(N); iota(cityOrd.begin(), cityOrd.end(), 0); sort(cityOrd.begin(), cityOrd.end(), [&](int a, int b) { return cityScore[a] > cityScore[b]; }); vector> pairOrd; pairOrd.reserve(N * (N - 1) / 2); for (int i = 0; i < N; ++i) { for (int j = i + 1; j < N; ++j) { long double v = pairWeight[i][j] + pairWeight[j][i]; pairOrd.emplace_back(v, i, j); } } sort(pairOrd.begin(), pairOrd.end(), [&](const auto& a, const auto& b) { return get<0>(a) > get<0>(b); }); vector candidates; vector> candidateFlights; vector staticPotential; vector candidateCityMask; unordered_set seenPlan; auto addCandidate = [&](const PlanePlan& p) { if ((int)p.route.size() <= 1) return; string key; key.reserve(16 + p.route.size() * 4); key += to_string(p.offset); key.push_back('|'); for (int c : p.route) { key += to_string(c); key.push_back(','); } if (seenPlan.find(key) != seenPlan.end()) return; vector fl; appendPlaneFlights(p, dur, fl); if (fl.empty()) return; long double pot = 0.0L; for (const auto& f : fl) { long double base = pairWeight[f.a][f.b]; if (base <= 0.0L) continue; for (int k = 0; k < TARGET_CNT; ++k) { int target = TARGET_START + TARGET_STEP * k; if (f.t <= target && f.s > sqBest[k][f.a][f.b]) pot += base; } } candidates.push_back(p); candidateFlights.push_back(std::move(fl)); staticPotential.push_back(pot); uint64_t mask = 0ULL; for (int c : p.route) mask |= (1ULL << c); candidateCityMask.push_back(mask); seenPlan.insert(std::move(key)); }; vector offsets = {0, 12, 24, 36, 48, 60}; int topPairs = min((int)pairOrd.size(), 220); for (int id = 0; id < topPairs; ++id) { auto [v, a, b] = pairOrd[id]; if (v <= 0.0L) break; for (int off : offsets) { addCandidate(buildCyclicPlan({a, b}, off, dur)); addCandidate(buildCyclicPlan({b, a}, off, dur)); } } int hubCnt = min(6, N); int spokeCnt = min(14, N); vector hubs(cityOrd.begin(), cityOrd.begin() + hubCnt); vector spokes(cityOrd.begin(), cityOrd.begin() + spokeCnt); for (int h : hubs) { for (int a : spokes) { if (a == h) continue; for (int b : spokes) { if (b == h || b == a) continue; for (int off : vector{6, 30, 54}) { addCandidate(buildCyclicPlan({h, a, h, b}, off, dur)); } } } } // Cover all cities: for each city, add shuttle plans to several strong partners. for (int c = 0; c < N; ++c) { vector> partner; partner.reserve(N - 1); for (int o = 0; o < N; ++o) { if (o == c) continue; long double v = pairWeight[c][o] + pairWeight[o][c]; v += 0.05L * (cityScore[c] + cityScore[o]); partner.push_back({v, o}); } sort(partner.begin(), partner.end(), [&](const auto& a, const auto& b) { return a.first > b.first; }); int take = min(5, (int)partner.size()); for (int i = 0; i < take; ++i) { int p = partner[i].second; for (int off : vector{0, 18, 36, 54}) { addCandidate(buildCyclicPlan({c, p}, off, dur)); addCandidate(buildCyclicPlan({p, c}, off, dur)); } } } // Multiple rings over different city-score bands. int ringLen = min(8, N); if (ringLen >= 4) { for (int st = 0; st < N; st += 6) { vector ring; for (int i = st; i < min(N, st + ringLen); ++i) ring.push_back(cityOrd[i]); if ((int)ring.size() < 4) continue; for (int off : vector{0, 24, 48}) { addCandidate(buildCyclicPlan(ring, off, dur)); vector rev = ring; reverse(rev.begin(), rev.end()); addCandidate(buildCyclicPlan(rev, off, dur)); } } } vector candOrd((int)candidates.size()); iota(candOrd.begin(), candOrd.end(), 0); sort(candOrd.begin(), candOrd.end(), [&](int a, int b) { return staticPotential[a] > staticPotential[b]; }); vector plans; plans.reserve(K); vector currentFlights; vector used(candidates.size(), 0); vector cityUse(N, 0); uint64_t coveredMask = 0ULL; int uniqueCities = 0; int targetUnique = min(N, 16); long double maxCityScore = 1.0L; for (int i = 0; i < N; ++i) maxCityScore = max(maxCityScore, cityScore[i]); long double avgPotential = 1.0L; if (!staticPotential.empty()) { long double sum = 0.0L; for (long double p : staticPotential) sum += p; avgPotential = max((long double)1.0, sum / (long double)staticPotential.size()); } for (int step = 0; step < K; ++step) { vector> dyn; vector> dynUncovered; dyn.reserve(candidates.size()); dynUncovered.reserve(candidates.size()); for (int id : candOrd) { if (used[id]) continue; uint64_t m = candidateCityMask[id]; long double novelty = 0.0L; while (m) { int c = __builtin_ctzll(m); novelty += (cityScore[c] / maxCityScore) / (1.0L + (long double)cityUse[c]); m &= (m - 1); } uint64_t uncovered = candidateCityMask[id] & (~coveredMask); int uncoveredCnt = __builtin_popcountll(uncovered); long double potNorm = staticPotential[id] / avgPotential; long double rank = potNorm + 0.60L * novelty + 0.90L * (long double)uncoveredCnt; dyn.push_back({rank, id}); dynUncovered.push_back({uncoveredCnt, id}); } sort(dyn.begin(), dyn.end(), [&](const auto& a, const auto& b) { return a.first > b.first; }); sort(dynUncovered.begin(), dynUncovered.end(), [&](const auto& a, const auto& b) { if (a.first != b.first) return a.first > b.first; return staticPotential[a.second] > staticPotential[b.second]; }); vector shortlist; int shortlistSize = 70; shortlist.reserve(shortlistSize); for (int i = 0; i < min(shortlistSize, (int)dyn.size()); ++i) shortlist.push_back(dyn[i].second); if (uniqueCities < targetUnique) { for (int i = 0; i < min(40, (int)dynUncovered.size()); ++i) { int id = dynUncovered[i].second; bool dup = false; for (int x : shortlist) { if (x == id) { dup = true; break; } } if (!dup) shortlist.push_back(id); } } if (shortlist.empty()) break; int bestId = shortlist[0]; double bestScore = -1.0; double bestObjective = -1.0; double exploreCoef = 0.0; if (uniqueCities < targetUnique) { exploreCoef = 0.010 * (double)(targetUnique - uniqueCities) / (double)targetUnique; } for (int id : shortlist) { vector testFlights = currentFlights; testFlights.insert(testFlights.end(), candidateFlights[id].begin(), candidateFlights[id].end()); double s = evaluator.score(testFlights, demands); int uncoveredCnt = __builtin_popcountll(candidateCityMask[id] & (~coveredMask)); double objective = s + exploreCoef * (double)uncoveredCnt; if (objective > bestObjective || (objective == bestObjective && s > bestScore)) { bestObjective = objective; bestScore = s; bestId = id; } } used[bestId] = 1; plans.push_back(candidates[bestId]); currentFlights.insert(currentFlights.end(), candidateFlights[bestId].begin(), candidateFlights[bestId].end()); uint64_t m = candidateCityMask[bestId]; while (m) { int c = __builtin_ctzll(m); if (cityUse[c] == 0) uniqueCities++; cityUse[c]++; m &= (m - 1); } coveredMask |= candidateCityMask[bestId]; } while ((int)plans.size() < K) plans.push_back(PlanePlan{{0}, 0, 0}); vector finalFlights = flattenPlans(plans, dur); double finalScore = evaluator.score(finalFlights, demands); for (int i = 0; i < K; ++i) { const auto& p = plans[i]; cout << max(0, (int)p.route.size() - 1) << '\n'; int tm = p.offset; for (int j = 1; j < (int)p.route.size(); ++j) { int a = p.route[j - 1], b = p.route[j]; int nt = tm + dur[a][b]; cout << (a + 1) << ' ' << slotToTime(tm) << ' ' << (b + 1) << ' ' << slotToTime(nt) << '\n'; tm = nt; } } cerr << fixed << setprecision(12) << "score=" << finalScore << " candidates=" << candidates.size() << " flights=" << finalFlights.size() << '\n'; return 0; }