use std::io::{self, Read}; const START_TIME: i32 = 6 * 60; const END_TIME: i32 = 21 * 60; const INF_NEG: i32 = -1_000_000_000; const BEAM_WIDTH: usize = 1; const HISTORY_LEN: usize = 10; const REFINE_ROUNDS: usize = 1; const TIME_EQ_MIN: i32 = 10; const SIGNATURE_BITS: usize = 2048; const SIGNATURE_WORDS: usize = SIGNATURE_BITS / 64; #[derive(Clone, Copy)] struct City { x: i32, y: i32, w: i64, } #[derive(Clone, Copy)] struct Flight { u: usize, v: usize, dep: i32, arr: i32, } #[derive(Clone, Copy)] #[allow(dead_code)] struct Opportunity { u: usize, v: usize, min_dep: i32, deadline: i32, points: i64, } fn read_value(it: &mut std::str::SplitWhitespace<'_>) -> T where T::Err: std::fmt::Debug, { it.next() .unwrap() .trim_start_matches('\u{feff}') .parse::() .unwrap() } fn parse_time(token: &str) -> i32 { let mut it = token.trim_start_matches('\u{feff}').split(':'); let h: i32 = it.next().unwrap().parse().unwrap(); let m: i32 = it.next().unwrap().parse().unwrap(); h * 60 + m } fn format_time(t: i32) -> String { format!("{:02}:{:02}", t / 60, t % 60) } fn distance(c1: City, c2: City) -> f64 { let dx = (c1.x - c2.x) as f64; let dy = (c1.y - c2.y) as f64; (dx * dx + dy * dy).sqrt() } fn required_duration(c1: City, c2: City) -> i32 { let d = distance(c1, c2); let raw = 60.0 * d / 800.0 + 40.0; (raw / 5.0).ceil() as i32 * 5 } fn target_deadlines() -> Vec { (0..=20).map(|i| 11 * 60 + i * 30).collect() } fn sort_by_dep_desc(mut flights: Vec) -> Vec { flights.sort_by_key(|f| -f.dep); flights } fn compute_latest_departure( n: usize, flights_desc: &[Flight], dest: usize, deadline: i32, ) -> Vec { let mut latest = vec![INF_NEG; n]; latest[dest] = deadline; for &f in flights_desc { if f.arr <= latest[f.v] { latest[f.u] = latest[f.u].max(f.dep); } } latest } fn make_far_pair_table(cities: &[City], r: i32) -> Vec> { let n = cities.len(); let threshold = r as f64 * 0.25; let mut far = vec![vec![false; n]; n]; for i in 0..n { for j in 0..n { far[i][j] = distance(cities[i], cities[j]) >= threshold; } } far } fn enumerate_opportunities(cities: &[City], r: i32, square_desc: &[Flight]) -> Vec { let n = cities.len(); let far = make_far_pair_table(cities, r); let deadlines = target_deadlines(); let mut opportunities = Vec::new(); for &deadline in &deadlines { for dest in 0..n { let latest_sq = compute_latest_departure(n, square_desc, dest, deadline); for src in 0..n { if !far[src][dest] { continue; } let s_sq = latest_sq[src]; let min_dep = if s_sq < START_TIME { START_TIME } else { s_sq + 5 }; opportunities.push(Opportunity { u: src, v: dest, min_dep, deadline, points: cities[src].w * cities[dest].w, }); } } } opportunities } fn precompute_latest_table( n: usize, flights_desc: &[Flight], deadlines: &[i32], ) -> Vec>> { let mut table = Vec::with_capacity(deadlines.len()); for &deadline in deadlines { let mut by_dest = Vec::with_capacity(n); for dest in 0..n { by_dest.push(compute_latest_departure(n, flights_desc, dest, deadline)); } table.push(by_dest); } table } fn precompute_durations(cities: &[City]) -> Vec> { let n = cities.len(); let mut d = vec![vec![0; n]; n]; for i in 0..n { for j in 0..n { if i == j { continue; } d[i][j] = required_duration(cities[i], cities[j]); } } d } fn top_k_cities_by_population(cities: &[City], k: usize) -> Vec { let mut ids: Vec = (0..cities.len()).collect(); ids.sort_by_key(|&i| std::cmp::Reverse(cities[i].w)); ids.truncate(k); ids } #[derive(Clone)] struct BeamState { score_est: i128, route: Vec, history_tail: Vec<(usize, i32, i32)>, used_signature: [u64; SIGNATURE_WORDS], } #[derive(Clone, Copy)] struct BeamOpp { id: usize, min_dep: i32, deadline: i32, points: i128, } fn bit_test(bits: &[u64], idx: usize) -> bool { let x = idx as u64; let h = x.wrapping_mul(0x9E3779B185EBCA87u64) as usize & (SIGNATURE_BITS - 1); (bits[h >> 6] >> (h & 63)) & 1 == 1 } fn bit_set(bits: &mut [u64], idx: usize) { let x = idx as u64; let h = x.wrapping_mul(0x9E3779B185EBCA87u64) as usize & (SIGNATURE_BITS - 1); bits[h >> 6] |= 1u64 << (h & 63); } fn insert_beam(bucket: &mut Vec, cand: BeamState) { bucket.push(cand); bucket.sort_by_key(|s| std::cmp::Reverse(s.score_est)); if bucket.len() > BEAM_WIDTH { bucket.truncate(BEAM_WIDTH); } } fn build_opportunities_with_fixed( cities: &[City], far: &[Vec], latest_sq_table: &[Vec>], latest_fixed_table: &[Vec>], deadlines: &[i32], ) -> (Vec>>, usize) { let n = cities.len(); let dlen = deadlines.len(); let mut opp_by_uv = vec![vec![Vec::::new(); n]; n]; let mut id_counter = 0usize; for u in 0..n { for v in 0..n { if !far[u][v] { continue; } let points = (cities[u].w as i128) * (cities[v].w as i128); for d_idx in 0..dlen { let sq = latest_sq_table[d_idx][v][u]; let fixed = latest_fixed_table[d_idx][v][u]; if fixed > sq { continue; } let base = sq.max(fixed); let min_dep = if base < START_TIME { START_TIME } else { base + 5 }; if min_dep > deadlines[d_idx] { continue; } opp_by_uv[u][v].push(BeamOpp { id: id_counter, min_dep, deadline: deadlines[d_idx], points, }); id_counter += 1; } } } (opp_by_uv, id_counter) } fn beam_search_single_plane( start_city: usize, opp_by_uv: &[Vec>], durations: &[Vec], ) -> Vec { let n = durations.len(); let mut time_points = Vec::new(); let mut t = START_TIME; while t < END_TIME { time_points.push(t); t += TIME_EQ_MIN; } if *time_points.last().unwrap() != END_TIME { time_points.push(END_TIME); } let tlen = time_points.len(); let mut dp: Vec>> = vec![vec![Vec::new(); n]; tlen]; dp[0][start_city].push(BeamState { score_est: 0, route: Vec::new(), history_tail: Vec::new(), used_signature: [0; SIGNATURE_WORDS], }); for t_idx in 0..tlen { let cur_time = time_points[t_idx]; for city in 0..n { let states = dp[t_idx][city].clone(); for st in states { if t_idx + 1 < tlen { insert_beam(&mut dp[t_idx + 1][city], st.clone()); } for v in 0..n { if v == city { continue; } let duration = durations[city][v]; let arr = cur_time + duration; if arr > END_TIME { continue; } let arr_t_idx = time_points.partition_point(|&x| x < arr); if arr_t_idx >= tlen { continue; } let mut gain: i128 = 0; for &opp in &opp_by_uv[city][v] { if arr <= opp.deadline && cur_time >= opp.min_dep { if !bit_test(&st.used_signature, opp.id) { gain += opp.points; } } } let mut should_expand = true; if BEAM_WIDTH > 0 && !dp[arr_t_idx][v].is_empty() { let worst = dp[arr_t_idx][v].last().unwrap().score_est; if dp[arr_t_idx][v].len() >= BEAM_WIDTH && st.score_est + gain <= worst { should_expand = false; } } if !should_expand { continue; } let mut ns = st.clone(); ns.score_est += gain; ns.route.push(Flight { u: city, v, dep: cur_time, arr, }); ns.history_tail.push((v, arr, cur_time)); if ns.history_tail.len() > HISTORY_LEN { let drop = ns.history_tail.len() - HISTORY_LEN; ns.history_tail.drain(0..drop); } for &opp in &opp_by_uv[city][v] { if arr <= opp.deadline && cur_time >= opp.min_dep { bit_set(&mut ns.used_signature, opp.id); } } insert_beam(&mut dp[arr_t_idx][v], ns); } } } } let mut best: Option = None; for layer in &dp { for bucket in layer { for st in bucket { if best .as_ref() .map(|b| st.score_est > b.score_est) .unwrap_or(true) { best = Some(st.clone()); } } } } best.map(|b| b.route).unwrap_or_default() } fn optimize_planes_with_fixed_opportunities( cities: &[City], deadlines: &[i32], latest_sq_table: &[Vec>], far: &[Vec], durations: &[Vec], k: usize, ) -> Vec> { let n = cities.len(); let starts = top_k_cities_by_population(cities, k); let mut planes = vec![Vec::::new(); k]; for _round in 0..REFINE_ROUNDS { for pid in 0..k { let mut fixed = Vec::new(); for (i, route) in planes.iter().enumerate() { if i == pid { continue; } fixed.extend(route.iter().copied()); } let fixed_desc = sort_by_dep_desc(fixed); let latest_fixed = precompute_latest_table(n, &fixed_desc, deadlines); let (opp_by_uv, opp_count) = build_opportunities_with_fixed( cities, far, latest_sq_table, &latest_fixed, deadlines, ); let _ = opp_count; planes[pid] = beam_search_single_plane(starts[pid], &opp_by_uv, durations); } } planes } fn compute_score(cities: &[City], r: i32, square_desc: &[Flight], circle_desc: &[Flight]) -> i64 { let n = cities.len(); let far = make_far_pair_table(cities, r); let deadlines = target_deadlines(); let mut v_sq: i128 = 0; let mut v_ci: i128 = 0; for &deadline in &deadlines { for dest in 0..n { let latest_sq = compute_latest_departure(n, square_desc, dest, deadline); let latest_ci = compute_latest_departure(n, circle_desc, dest, deadline); for src in 0..n { if !far[src][dest] { continue; } let points = (cities[src].w as i128) * (cities[dest].w as i128); if latest_sq[src] < latest_ci[src] { v_ci += points; } else { v_sq += points; } } } } let total = v_sq + v_ci; if total == 0 { 0 } else { (1_000_000i128 * v_ci / total) as i64 } } fn main() { let mut input = String::new(); io::stdin().read_to_string(&mut input).unwrap(); let mut it = input.split_whitespace(); let n: usize = read_value(&mut it); let r: i32 = read_value(&mut it); let mut cities = Vec::with_capacity(n); for _ in 0..n { let x: i32 = read_value(&mut it); let y: i32 = read_value(&mut it); let w: i64 = read_value(&mut it); cities.push(City { x, y, w }); } let m: usize = read_value(&mut it); let mut square = Vec::with_capacity(m); for _ in 0..m { let a: usize = read_value::(&mut it) - 1; let s_token: String = read_value(&mut it); let b: usize = read_value::(&mut it) - 1; let t_token: String = read_value(&mut it); square.push(Flight { u: a, v: b, dep: parse_time(&s_token), arr: parse_time(&t_token), }); } let k: usize = read_value(&mut it); let square_desc = sort_by_dep_desc(square.clone()); let far = make_far_pair_table(&cities, r); let durations = precompute_durations(&cities); let deadlines = target_deadlines(); let latest_sq_table = precompute_latest_table(n, &square_desc, &deadlines); let planes = optimize_planes_with_fixed_opportunities( &cities, &deadlines, &latest_sq_table, &far, &durations, k, ); for plane in &planes { for (idx, f) in plane.iter().enumerate() { let need = durations[f.u][f.v]; assert_eq!(f.arr - f.dep, need); assert!((START_TIME..=END_TIME).contains(&f.dep)); assert!((START_TIME..=END_TIME).contains(&f.arr)); assert_eq!(f.dep % 5, 0); assert_eq!(f.arr % 5, 0); if idx > 0 { let prev = plane[idx - 1]; assert_eq!(prev.v, f.u); assert!(prev.arr <= f.dep); } } } let opportunities = enumerate_opportunities(&cities, r, &square_desc); let circle: Vec = planes.iter().flat_map(|v| v.iter().copied()).collect(); let score = compute_score(&cities, r, &square_desc, &sort_by_dep_desc(circle.clone())); eprintln!("opportunities={}", opportunities.len()); let opportunity_points: i128 = opportunities.iter().map(|o| o.points as i128).sum(); eprintln!("opportunity_points={}", opportunity_points); let selected_count: usize = planes.iter().map(|v| v.len()).sum(); eprintln!("selected_flights={}", selected_count); eprintln!("beam_width={}", BEAM_WIDTH); eprintln!("history_len={}", HISTORY_LEN); eprintln!("refine_rounds={}", REFINE_ROUNDS); eprintln!("time_eq_min={}", TIME_EQ_MIN); eprintln!("score={}", score); for plane in &planes { println!("{}", plane.len()); for f in plane { println!( "{} {} {} {}", f.u + 1, format_time(f.dep), f.v + 1, format_time(f.arr) ); } } }