// #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") // #pragma GCC optimize("Ofast") #include using namespace std; constexpr bool DEBUG = true; constexpr double TIME_LIMIT = 1.95; // Macros #define el '\n' #define all(v) (v).begin(), (v).end() using i8 = int8_t; using u8 = uint8_t; using i16 = int16_t; using u16 = uint16_t; using i32 = int32_t; using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; using f32 = float; using f64 = double; #define rep(i, n) for (i64 i = 0; i < (i64)(n); i++) template using min_queue = priority_queue, greater>; template using max_queue = priority_queue; // Constant const double pi = 3.141592653589793238; const i32 inf32 = 1073741823; const i64 inf64 = 1LL << 60; const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const string abc = "abcdefghijklmnopqrstuvwxyz"; const int MOD = 998244353; const array dx = {0, 0, -1, 1, -1, -1, 1, 1}; const array dy = {-1, 1, 0, 0, -1, 1, -1, 1}; // Printing template void print_collection(ostream &out, T const &x); template void print_tuple(ostream &out, T const &a, index_sequence); namespace std { template ostream &operator<<(ostream &out, tuple const &x) { print_tuple(out, x, index_sequence_for{}); return out; } template ostream &operator<<(ostream &out, pair const &x) { print_tuple(out, x, index_sequence_for{}); return out; } template ostream &operator<<(ostream &out, array const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, vector const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, deque const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, multiset const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, multimap const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, set const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, map const &x) { print_collection(out, x); return out; } template ostream &operator<<(ostream &out, unordered_set const &x) { print_collection(out, x); return out; } } // namespace std template void print_tuple(ostream &out, T const &a, index_sequence) { using swallow = int[]; out << '('; (void)swallow{0, (void(out << (I == 0 ? "" : ", ") << get(a)), 0)...}; out << ')'; } template void print_collection(ostream &out, T const &x) { int f = 0; out << '['; for (auto const &i : x) { out << (f++ ? "," : ""); out << i; } out << "]"; } // Random struct RNG { uint64_t s[2]; RNG(u64 seed) { reset(seed); } RNG() { reset(time(0)); } using result_type = u32; static constexpr u32 min() { return numeric_limits::min(); } static constexpr u32 max() { return numeric_limits::max(); } u32 operator()() { return randomInt32(); } static __attribute__((always_inline)) inline uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } inline void reset(u64 seed) { struct splitmix64_state { u64 s; u64 splitmix64() { u64 result = (s += 0x9E3779B97f4A7C15); result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; result = (result ^ (result >> 27)) * 0x94D049BB133111EB; return result ^ (result >> 31); } }; splitmix64_state sm{seed}; s[0] = sm.splitmix64(); s[1] = sm.splitmix64(); } uint64_t next() { const uint64_t s0 = s[0]; uint64_t s1 = s[1]; const uint64_t result = rotl(s0 * 5, 7) * 9; s1 ^= s0; s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b s[1] = rotl(s1, 37); // c return result; } inline u32 randomInt32() { return next(); } inline u64 randomInt64() { return next(); } inline u32 random32(u32 r) { return (((u64)randomInt32()) * r) >> 32; } inline u64 random64(u64 r) { return randomInt64() % r; } inline u32 randomRange32(u32 l, u32 r) { return l + random32(r - l + 1); } inline u64 randomRange64(u64 l, u64 r) { return l + random64(r - l + 1); } inline double randomDouble() { return (double)randomInt32() / 4294967296.0; } inline double randomDoubleOpen01() { return (randomInt32() + 1.0) / 4294967297.0; } inline float randomFloat() { return (float)randomInt32() / 4294967296.0; } inline double randomRangeDouble(double l, double r) { return l + randomDouble() * (r - l); } inline double randomGaussian(double mean = 0.0, double stddev = 1.0) { double u1 = randomDoubleOpen01(); double u2 = randomDouble(); double z = sqrt(-2.0 * log(u1)) * cos(2.0 * 3.141592653589793238 * u2); return mean + stddev * z; } template void shuffle(vector &v) { i32 sz = v.size(); for (i32 i = sz; i > 1; i--) { i32 p = random32(i); swap(v[i - 1], v[p]); } } template void shuffle(T *fr, T *to) { i32 sz = distance(fr, to); for (int i = sz; i > 1; i--) { int p = random32(i); swap(fr[i - 1], fr[p]); } } template inline int sample_index(vector const &v) { return random32(v.size()); } template inline T sample(vector const &v) { return v[sample_index(v)]; } } rng; class FenwickWeightedSampler { private: int n_ = 0; vector bit_; vector weight_; double total_ = 0.0; void add_internal(int idx0, double delta) { int i = idx0 + 1; while (i <= n_) { bit_[i] += delta; i += i & -i; } } public: // Complexity: O(n) void init(int n, double initial_weight = 0.0) { n_ = n; bit_.assign(n_ + 1, 0.0); weight_.assign(n_, initial_weight); total_ = 0.0; if (initial_weight != 0.0) { for (int i = 0; i < n_; i++) { add_internal(i, initial_weight); } total_ = initial_weight * n_; } } // Complexity: O(n log n) void build(const vector &weights) { init((int)weights.size(), 0.0); for (int i = 0; i < n_; i++) { weight_[i] = weights[i]; add_internal(i, weights[i]); total_ += weights[i]; } } // Complexity: O(log n) void set_weight(int idx, double new_weight) { assert(0 <= idx && idx < n_); const double delta = new_weight - weight_[idx]; weight_[idx] = new_weight; add_internal(idx, delta); total_ += delta; } // Complexity: O(log n) void add_weight(int idx, double delta) { assert(0 <= idx && idx < n_); weight_[idx] += delta; add_internal(idx, delta); total_ += delta; } // Complexity: O(log n) int sample() const { assert(n_ > 0); assert(total_ > 0.0); const double r = rng.randomDouble() * total_; int idx = 0; double prefix = 0.0; int step = 1; while ((step << 1) <= n_) step <<= 1; for (int k = step; k > 0; k >>= 1) { const int nxt = idx + k; if (nxt <= n_ && prefix + bit_[nxt] <= r) { idx = nxt; prefix += bit_[nxt]; } } if (idx >= n_) idx = n_ - 1; return idx; } int size() const { return n_; } double total_weight() const { return total_; } double weight(int idx) const { assert(0 <= idx && idx < n_); return weight_[idx]; } }; class AliasWeightedSampler { private: int n_ = 0; vector weight_; double total_ = 0.0; vector prob_; vector alias_; bool dirty_ = true; // Complexity: O(n) void rebuild_alias_table() { prob_.assign(n_, 0.0); alias_.assign(n_, 0); total_ = 0.0; for (double w : weight_) total_ += w; assert(total_ > 0.0); vector scaled(n_); vector small; vector large; small.reserve(n_); large.reserve(n_); for (int i = 0; i < n_; i++) { scaled[i] = weight_[i] * n_ / total_; if (scaled[i] < 1.0) { small.push_back(i); } else { large.push_back(i); } } while (!small.empty() && !large.empty()) { const int s = small.back(); small.pop_back(); const int l = large.back(); large.pop_back(); prob_[s] = scaled[s]; alias_[s] = l; scaled[l] -= (1.0 - scaled[s]); if (scaled[l] < 1.0) { small.push_back(l); } else { large.push_back(l); } } while (!large.empty()) { const int i = large.back(); large.pop_back(); prob_[i] = 1.0; alias_[i] = i; } while (!small.empty()) { const int i = small.back(); small.pop_back(); prob_[i] = 1.0; alias_[i] = i; } dirty_ = false; } public: // Complexity: O(n) void init(int n, double initial_weight = 0.0) { n_ = n; weight_.assign(n_, initial_weight); total_ = initial_weight * n_; prob_.clear(); alias_.clear(); dirty_ = true; } // Complexity: O(n) void build(const vector &weights) { n_ = (int)weights.size(); weight_ = weights; dirty_ = true; // Build lazily on sample() to allow batch updates before first use. } // Complexity: O(1), table becomes dirty void set_weight(int idx, double new_weight) { assert(0 <= idx && idx < n_); weight_[idx] = new_weight; dirty_ = true; } // Complexity: O(1), table becomes dirty void add_weight(int idx, double delta) { assert(0 <= idx && idx < n_); weight_[idx] += delta; dirty_ = true; } // Complexity: O(1) after table is ready, O(n) if rebuild is needed int sample() { assert(n_ > 0); if (dirty_) rebuild_alias_table(); const int i = (int)rng.random32((uint32_t)n_); return (rng.randomDouble() < prob_[i]) ? i : alias_[i]; } int size() const { return n_; } double total_weight() { if (dirty_) rebuild_alias_table(); return total_; } double weight(int idx) const { assert(0 <= idx && idx < n_); return weight_[idx]; } }; // Timer struct Timer { chrono::steady_clock::time_point t_begin; Timer() { t_begin = chrono::steady_clock::now(); } void reset() { t_begin = chrono::steady_clock::now(); } float elapsed() const { return chrono::duration(chrono::steady_clock::now() - t_begin) .count(); } } timer; // Util template T &smin(T &x, T const &y) { x = min(x, y); return x; } template T &smax(T &x, T const &y) { x = max(x, y); return x; } template int sgn(T val) { if (val < 0) return -1; if (val > 0) return 1; return 0; } static inline string int_to_string(int val, int digits = 0) { string s = to_string(val); reverse(begin(s), end(s)); while ((int)s.size() < digits) s.push_back('0'); reverse(begin(s), end(s)); return s; } // Debug static inline void debug() { cerr << "\n"; } template void debug(T const &t, V const &...v) { if constexpr (DEBUG) { cerr << t; if (sizeof...(v)) { cerr << ", "; } debug(v...); } } // Bits __attribute__((always_inline)) inline u64 bit(u64 x) { return 1ull << x; } __attribute__((always_inline)) inline void setbit(u64 &a, u32 b, u64 value = 1) { a = (a & ~bit(b)) | (value << b); } __attribute__((always_inline)) inline u64 getbit(u64 a, u32 b) { return (a >> b) & 1; } __attribute__((always_inline)) inline u64 lsb(u64 a) { return __builtin_ctzll(a); } __attribute__((always_inline)) inline int msb(uint64_t bb) { return __builtin_clzll(bb) ^ 63; } struct Init { Init() { ios::sync_with_stdio(0); cin.tie(0); } } init; // ========================================== // Input & State // ========================================== struct Flight { i32 from = -1; i32 to = -1; i32 dep = -1; i32 arr = -1; }; constexpr i32 START_MIN = 6 * 60; constexpr i32 END_MIN = 21 * 60; constexpr i32 STEP_MIN = 5; struct Input { i32 N = 0, R = 0, M = 0, K = 0; vector x, y; vector w; vector sq_flights; static i32 parse_time(string const &s) { i32 hh = stoi(s.substr(0, 2)); i32 mm = stoi(s.substr(3, 2)); return hh * 60 + mm; } void input() { string head; cin >> head; if (!head.empty() && (unsigned char)head[0] == 0xEF) { if (head.size() >= 3 && (unsigned char)head[1] == 0xBB && (unsigned char)head[2] == 0xBF) { head = head.substr(3); } } N = stoi(head); cin >> R; x.resize(N); y.resize(N); w.resize(N); rep(i, N) { cin >> x[i] >> y[i] >> w[i]; } cin >> M; sq_flights.resize(M); rep(i, M) { i32 a, b; string s, t; cin >> a >> s >> b >> t; --a; --b; sq_flights[i] = Flight{a, b, parse_time(s), parse_time(t)}; } cin >> K; } } in; // ========================================== // Solver // ========================================== class Solver { struct PairInfo { i16 src = -1; i16 dst = -1; i64 gain = 0; }; vector targets; vector> duration; vector pair_infos; vector> best_plan; double best_share = -1.0; vector dp_sq_flat; vector dp_ci_flat; __int128 total_gain_all = 0; inline i32 dp_index(i32 dest, i32 k, i32 src) const { return (dest * (i32)targets.size() + k) * in.N + src; } static string format_time(i32 m) { i32 hh = m / 60; i32 mm = m % 60; string res = int_to_string(hh, 2) + ":" + int_to_string(mm, 2); return res; } static i32 flight_duration_min(double d) { double raw = 60.0 * d / 800.0 + 40.0; i32 v = (i32)ceil(raw / 5.0) * 5; return v; } static void sort_desc_inplace(vector &flights) { sort(all(flights), [](Flight const &l, Flight const &r) { if (l.dep != r.dep) return l.dep > r.dep; return l.arr > r.arr; }); } void compute_all_dp_flat_sorted(vector const &flights_sorted, vector &out_dp) { i32 N = in.N; i32 TK = (i32)targets.size(); out_dp.assign(N * TK * N, -1); rep(dest, N) { rep(k, TK) { i16 *cur = out_dp.data() + dp_index((i32)dest, (i32)k, 0); cur[dest] = (i16)targets[k]; for (auto const &e : flights_sorted) { if (cur[e.to] >= e.arr && e.dep > cur[e.from]) { cur[e.from] = (i16)e.dep; } } } } } double evaluate_share(vector> const &plan) { vector ci; ci.reserve(512); for (auto const &vec : plan) { for (auto const &f : vec) ci.push_back(f); } sort_desc_inplace(ci); compute_all_dp_flat_sorted(ci, dp_ci_flat); __int128 v_ci = 0; for (auto const &pi : pair_infos) { __int128 gain = (__int128)pi.gain; rep(k, targets.size()) { i16 s_sq = dp_sq_flat[dp_index(pi.dst, (i32)k, pi.src)]; i16 s_ci = dp_ci_flat[dp_index(pi.dst, (i32)k, pi.src)]; if (s_sq < s_ci) v_ci += gain; } } if (total_gain_all == 0) return 0.0; return (double)v_ci / (double)total_gain_all; } vector> build_random_plan() { i32 N = in.N; i32 K = in.K; vector> plan(K); rep(p, K) { i32 cur_city = rng.random32(N); i32 cur_time = START_MIN; plan[p].reserve(16); while (true) { i32 dst = rng.random32(N - 1); if (dst >= cur_city) ++dst; i32 dur = duration[cur_city][dst]; i32 dep = cur_time; // 到着後は即時出発 i32 arr = dep + dur; if (arr > END_MIN) break; plan[p].push_back(Flight{cur_city, dst, dep, arr}); cur_city = dst; cur_time = arr; } } return plan; } public: Solver() {} void solve() { i32 N = in.N; i32 R = in.R; for (i32 t = 11 * 60; t <= 21 * 60; t += 30) targets.push_back(t); duration.assign(N, vector(N, 0)); rep(i, N) { rep(j, N) { if (i == j) continue; double ddx = (double)in.x[i] - (double)in.x[j]; double ddy = (double)in.y[i] - (double)in.y[j]; double dist = sqrt(ddx * ddx + ddy * ddy); duration[i][j] = flight_duration_min(dist); if (dist >= 0.25 * (double)R) { pair_infos.push_back(PairInfo{(i16)i, (i16)j, in.w[i] * in.w[j]}); } } } total_gain_all = 0; for (auto const &pi : pair_infos) { total_gain_all += (__int128)pi.gain * (__int128)targets.size(); } vector sq_sorted = in.sq_flights; sort_desc_inplace(sq_sorted); compute_all_dp_flat_sorted(sq_sorted, dp_sq_flat); dp_ci_flat.resize(N * (i32)targets.size() * N, -1); best_plan.assign(in.K, {}); Timer local_timer; i64 iterations = 0; while (local_timer.elapsed() < 1.0f) { ++iterations; auto plan = build_random_plan(); double share = evaluate_share(plan); if (share > best_share) { double old_share = best_share; i64 old_score = (old_share < 0.0) ? -1 : (i64)floor(1000000.0 * old_share); i64 new_score = (i64)floor(1000000.0 * share); cerr << fixed << setprecision(6) << "improved: score " << old_score << " -> " << new_score << ", share " << old_share << " -> " << share << ", iter " << iterations << ", elapsed " << local_timer.elapsed() << "s" << el; best_share = share; best_plan = move(plan); } } cerr << "total_iterations: " << iterations << el; } void print() { rep(p, in.K) { cout << best_plan[p].size() << el; for (auto const &f : best_plan[p]) { cout << (f.from + 1) << ' ' << format_time(f.dep) << ' ' << (f.to + 1) << ' ' << format_time(f.arr) << el; } } } }; int main() { in.input(); Solver solver; solver.solve(); solver.print(); // 高速に終了する cout.flush(); cerr.flush(); _Exit(0); }