結果
問題 | No.5007 Steiner Space Travel |
ユーザー | shamio |
提出日時 | 2022-07-30 17:21:09 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 952 ms / 1,000 ms |
コード長 | 17,210 bytes |
コンパイル時間 | 1,132 ms |
実行使用メモリ | 6,952 KB |
スコア | 8,279,534 |
最終ジャッジ日時 | 2022-07-30 17:21:45 |
合計ジャッジ時間 | 32,647 ms |
ジャッジサーバーID (参考情報) |
judge14 / judge12 |
純コード判定しない問題か言語 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 952 ms
4,904 KB |
testcase_01 | AC | 951 ms
4,900 KB |
testcase_02 | AC | 951 ms
6,952 KB |
testcase_03 | AC | 950 ms
4,900 KB |
testcase_04 | AC | 951 ms
4,900 KB |
testcase_05 | AC | 952 ms
4,900 KB |
testcase_06 | AC | 951 ms
4,904 KB |
testcase_07 | AC | 951 ms
4,904 KB |
testcase_08 | AC | 952 ms
6,952 KB |
testcase_09 | AC | 952 ms
6,952 KB |
testcase_10 | AC | 951 ms
4,900 KB |
testcase_11 | AC | 951 ms
4,904 KB |
testcase_12 | AC | 951 ms
4,900 KB |
testcase_13 | AC | 950 ms
4,904 KB |
testcase_14 | AC | 950 ms
4,900 KB |
testcase_15 | AC | 951 ms
6,952 KB |
testcase_16 | AC | 951 ms
4,900 KB |
testcase_17 | AC | 951 ms
4,900 KB |
testcase_18 | AC | 951 ms
6,952 KB |
testcase_19 | AC | 951 ms
6,952 KB |
testcase_20 | AC | 951 ms
6,952 KB |
testcase_21 | AC | 951 ms
4,900 KB |
testcase_22 | AC | 951 ms
4,904 KB |
testcase_23 | AC | 952 ms
6,952 KB |
testcase_24 | AC | 951 ms
4,900 KB |
testcase_25 | AC | 950 ms
4,900 KB |
testcase_26 | AC | 951 ms
6,948 KB |
testcase_27 | AC | 951 ms
4,900 KB |
testcase_28 | AC | 951 ms
4,904 KB |
testcase_29 | AC | 951 ms
4,904 KB |
コンパイルメッセージ
warning: unnecessary parentheses around method argument --> Main.rs:178:35 | 178 | let j = i + self.next((a.len() - i)) as usize; | ^ ^ | = note: `#[warn(unused_parens)]` on by default help: remove these parentheses | 178 - let j = i + self.next((a.len() - i)) as usize; 178 + let j = i + self.next(a.len() - i) as usize; | warning: unused variable: `energies` --> Main.rs:236:5 | 236 | energies: &[[i32; NUM_COMMETS]; NUM_COMMETS], | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_energies` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `score` --> Main.rs:547:9 | 547 | let score = (1_000_000_000.0 / (1000.0 + (sum_energies as f64).sqrt())).round() as i32; | ^^^^^ help: if this is intentional, prefix it with an underscore: `_score` warning: variable does not need to be mutable --> Main.rs:303:9 | 303 | let mut x_station = (x_sum as f64 / (2.0 * commets_arround_station.len() as f64)) as i32; | ----^^^^^^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> Main.rs:304:9 | 304 | let mut y_station = (y_sum as f64 / (2.0 * commets_arround_station.len() as f64)) as i32; | ----^^^^^^^^^ | | | help: remove this `mut` warning: constant is never used: `D` --> Main.rs:189:1 | 189 | const D: [(i32, i32); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` on by default warning: 6 warnings emitted
ソースコード
#[allow(unused_macros)] macro_rules! debug { ($($a:expr),*) => { #[cfg(feature = "single_testcase")] { eprint!("[line:{}] ", line!()); eprintln!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*); } } } fn get_time() -> f64 { static mut STIME: f64 = -1.0; let t = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap(); let ms = t.as_secs() as f64 + t.subsec_nanos() as f64 * 1e-9; unsafe { if STIME < 0.0 { STIME = ms; } ms - STIME } } //-------------------------------------------------------------------------------- // https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8#%E8%BF%BD%E8%A8%98-%E9%81%85%E5%BB%B6%E5%85%A5%E5%8A%9B #[allow(unused_macros)] macro_rules! input { (source = $s:expr, $($r:tt)*) => { let mut iter = $s.split_whitespace(); let mut next = || { iter.next().unwrap() }; input_inner!{next, $($r)*} }; ($($r:tt)*) => { let stdin = std::io::stdin(); let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); let mut next = move || -> String{ bytes .by_ref() .map(|r|r.unwrap() as char) .skip_while(|c|c.is_whitespace()) .take_while(|c|!c.is_whitespace()) .collect() }; input_inner!{next, $($r)*} }; } #[allow(unused_macros)] macro_rules! input_inner { ($next:expr) => {}; ($next:expr, ) => {}; ($next:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($next, $t); input_inner!{$next $($r)*} }; } #[allow(unused_macros)] macro_rules! read_value { ($next:expr, ( $($t:tt),* )) => { ( $(read_value!($next, $t)),* ) }; ($next:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() }; ($next:expr, chars) => { read_value!($next, String).chars().collect::<Vec<char>>() }; ($next:expr, usize1) => { read_value!($next, usize) - 1 }; ($next:expr, $t:ty) => { $next().parse::<$t>().expect("Parse error") }; } //-------------------------------------------------------------------------------- // https://atcoder.jp/contests/intro-heuristics/submissions/14832097 #[allow(dead_code)] fn readln() -> String { let mut line = String::new(); ::std::io::stdin() .read_line(&mut line) .unwrap_or_else(|e| panic!("{}", e)); line } #[allow(unused_macros)] macro_rules! read { ($($t:tt),*; $n:expr) => {{ let stdin = ::std::io::stdin(); let ret = ::std::io::BufRead::lines(stdin.lock()).take($n).map(|line| { let line = line.unwrap(); let mut it = line.split_whitespace(); _read!(it; $($t),*) }).collect::<Vec<_>>(); ret }}; ($($t:tt),*) => {{ let line = readln(); let mut it = line.split_whitespace(); _read!(it; $($t),*) }}; } macro_rules! _read { ($it:ident; [char]) => { _read!($it; String).chars().collect::<Vec<_>>() }; ($it:ident; [u8]) => { Vec::from(_read!($it; String).into_bytes()) }; ($it:ident; usize1) => { $it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1 }; ($it:ident; [usize1]) => { $it.map(|s| s.parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::<Vec<_>>() }; ($it:ident; [$t:ty]) => { $it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::<Vec<_>>() }; ($it:ident; $t:ty) => { $it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<$t>().unwrap_or_else(|e| panic!("{}", e)) }; ($it:ident; $($t:tt),+) => { ($(_read!($it; $t)),*) }; } //-------------------------------------------------------------------------------- // https://atcoder.jp/contests/hokudai-hitachi2017-1/submissions/1797182 // u32 -> usize pub struct XorShift { pub x: [usize; 4], } impl XorShift { pub fn new(mut seed: usize) -> XorShift { let mut x = [0; 4]; for i in 0..4 { seed = 1812433253usize .wrapping_mul(seed ^ (seed >> 30)) .wrapping_add(i as usize); x[i] = seed; } XorShift { x: x } } pub fn next_usize(&mut self) -> usize { let t = self.x[0] ^ (self.x[0] << 11); for i in 0..3 { self.x[i] = self.x[i + 1] } self.x[3] = self.x[3] ^ (self.x[3] >> 19) ^ t ^ (t >> 8); self.x[3] } /// [0, n) pub fn next(&mut self, n: usize) -> usize { loop { let t = self.next_usize(); let r = t % n; if (t - r).checked_add(n).is_some() { return r; } } } pub fn shuffle<T>(&mut self, a: &mut [T]) { for i in 0..a.len() { let j = i + self.next((a.len() - i)) as usize; a.swap(i, j); } } } //-------------------------------------------------------------------------------- const SEED: u32 = 890482; const TIME_LIMIT: f64 = 0.95; const D: [(i32, i32); 4] = [(1, 0), (0, 1), (-1, 0), (0, -1)]; const NUM_COMMETS: usize = 100; const NUM_STATIONS: usize = 8; const ALPHA: i32 = 5; const ALPHAS: [i32; 3] = [ALPHA * ALPHA, ALPHA, 1]; #[allow(dead_code)] fn sample_output() { for _ in 0..NUM_STATIONS { eprintln!("{} {}", 0, 0); println!("{} {}", 0, 0); } let v = NUM_COMMETS + 1; eprintln!("{}", v); println!("{}", v); for i in 0..NUM_COMMETS { eprintln!("{} {}", 1, i + 1); println!("{} {}", 1, i + 1); } eprintln!("{} {}", 1, 1); println!("{} {}", 1, 1); } fn get_energy(x_from: i32, y_from: i32, x_to: i32, y_to: i32, which: usize) -> i32 { ((x_from - x_to) * (x_from - x_to) + (y_from - y_to) * (y_from - y_to)) * ALPHAS[which] } fn print_output(stations: &[(i32, i32)], route: &[usize]) { for &(x, y) in stations.iter() { println!("{} {}", x, y); } println!("{}", route.len()); for &i in route.iter() { if i < NUM_COMMETS { println!("{} {}", 1, i + 1); } else { println!("{} {}", 2, i + 1 - NUM_COMMETS); } } } fn compute_sum_energies_all( route: &[usize], stations: &[(i32, i32)], commets: &[(i32, i32)], energies: &[[i32; NUM_COMMETS]; NUM_COMMETS], ) -> i32 { let mut sum_energies = 0; for i in 0..route.len() - 1 { let from = route[i]; let to = route[i + 1]; let bl_from = from < NUM_COMMETS; let bl_to = to < NUM_COMMETS; let which = if bl_from && bl_to { 0 } else if bl_from || bl_to { 1 } else { 2 }; let (x_from, y_from) = if bl_from { commets[from] } else { stations[from - NUM_COMMETS] }; let (x_to, y_to) = if bl_to { commets[to] } else { stations[to - NUM_COMMETS] }; let energy = get_energy(x_from, y_from, x_to, y_to, which); sum_energies += energy; } sum_energies } fn is_station(i: usize) -> bool { i >= NUM_COMMETS } fn compute_station_energies( commets_arround_station: &[(usize, usize)], station: (i32, i32), commets: &[(i32, i32)], ) -> i32 { let (x_station, y_station) = station; let mut sum_energies = 0; for &(u, v) in commets_arround_station.iter() { let (xu, yu) = commets[u]; sum_energies += get_energy(xu, yu, x_station, y_station, 1); let (xv, yv) = commets[v]; sum_energies += get_energy(x_station, y_station, xv, yv, 1); } sum_energies } fn compute_best_station( commets_arround_station: &[(usize, usize)], commets: &[(i32, i32)], ) -> (i32, i32) { let mut x_sum = 0; let mut y_sum = 0; for &(u, v) in commets_arround_station.iter() { let (xu, yu) = commets[u]; x_sum += xu; y_sum += yu; let (xv, yv) = commets[v]; x_sum += xv; y_sum += yv; } let mut x_station = (x_sum as f64 / (2.0 * commets_arround_station.len() as f64)) as i32; let mut y_station = (y_sum as f64 / (2.0 * commets_arround_station.len() as f64)) as i32; // let mut sum_energies = // compute_station_energies(commets_arround_station, (x_station, y_station), commets); // for i in 0..1000 { // let mut best_di = None; // for (di, &(dx, dy)) in D.iter().enumerate() { // let next_x_station = x_station + dx; // let next_y_station = y_station + dy; // let next_sum_energies = compute_station_energies( // commets_arround_station, // (next_x_station, next_y_station), // commets, // ); // if next_sum_energies <= sum_energies { // best_di = Some(di); // sum_energies = next_sum_energies; // } // } // match best_di { // Some(best_di) => { // let (dx, dy) = D[best_di]; // x_station += dx; // y_station += dy; // } // None => { // debug!(i); // break; // } // } // } (x_station, y_station) } fn main() { get_time(); let mut xorshift = XorShift::new(SEED as usize); let (_n, _m) = read!(usize, usize); let mut commets = Vec::with_capacity(NUM_COMMETS); for _ in 0..NUM_COMMETS { let (x, y) = read!(i32, i32); commets.push((x, y)); } let mut energies = [[0; NUM_COMMETS]; NUM_COMMETS]; for (i, &(xi, yi)) in commets.iter().enumerate() { for (j, &(xj, yj)) in commets.iter().enumerate() { let energy = get_energy(xi, yi, xj, yj, 0); energies[i][j] = energy; } } let mut stations = [(0, 0); NUM_STATIONS]; for i in 0..NUM_STATIONS { let x = xorshift.next(1000) as i32; let y = xorshift.next(1000) as i32; stations[i] = (x, y); } let mut commets_arround_stations = vec![vec![]; NUM_STATIONS]; let mut route: Vec<usize> = (1..NUM_COMMETS).collect(); xorshift.shuffle(&mut route); route.insert(0, 0); route.push(0); let mut sum_energies: i32 = compute_sum_energies_all(&route, &stations, &commets, &energies); const NUM_NEIGHBORS: usize = 4; let neighbor_percentages = [10, 10, 10, 70]; // let neighbor_percentages = [100, 0, 0, 0]; // let neighbor_percentages = [0, 0, 0, 100]; let mut accumulate_percentages = [0; NUM_NEIGHBORS]; let mut acc = 0; for (i, &e) in neighbor_percentages.iter().enumerate() { acc += e; accumulate_percentages[i] = acc; } assert_eq!(accumulate_percentages[NUM_NEIGHBORS - 1], 100); for cnt in 1.. { if cnt % 128 == 0 && get_time() > TIME_LIMIT { debug!(cnt); break; } let which_neighbor = xorshift.next(100); if which_neighbor < accumulate_percentages[0] { // insert station // u(i) -> s -> v(i + 1) let i = xorshift.next(route.len() - 1); let u = route[i]; let v = route[i + 1]; if is_station(u) || is_station(v) { continue; } let (xu, yu) = commets[u]; let (xv, yv) = commets[v]; let si = xorshift.next(NUM_STATIONS); let mut next_sum_energies = sum_energies; next_sum_energies -= compute_station_energies(&commets_arround_stations[si], stations[si], &commets); next_sum_energies -= get_energy(xu, yu, xv, yv, 0); commets_arround_stations[si].push((u, v)); let next_station = compute_best_station(&commets_arround_stations[si], &commets); next_sum_energies += compute_station_energies(&commets_arround_stations[si], next_station, &commets); if next_sum_energies <= sum_energies { stations[si] = next_station; sum_energies = next_sum_energies; route.insert(i + 1, si + NUM_COMMETS); } else { commets_arround_stations[si].pop(); } } else if which_neighbor < accumulate_percentages[1] { // delete station let mut sum_stations = 0; for v in commets_arround_stations.iter() { sum_stations += v.len(); } if sum_stations == 0 { continue; } let mut idx = xorshift.next(sum_stations); let mut si = 0; let mut ci = 0; for (ssi, v) in commets_arround_stations.iter().enumerate() { if idx < v.len() { si = ssi; ci = idx; break; } else { idx -= v.len(); } } let mut next_sum_energies = sum_energies; next_sum_energies -= compute_station_energies(&commets_arround_stations[si], stations[si], &commets); let (u, v) = commets_arround_stations[si].swap_remove(ci); let (xu, yu) = commets[u]; let (xv, yv) = commets[v]; next_sum_energies += compute_station_energies(&commets_arround_stations[si], stations[si], &commets); next_sum_energies += get_energy(xu, yu, xv, yv, 0); if next_sum_energies <= sum_energies { sum_energies = next_sum_energies; let mut idx = 0; for i in 1..route.len() - 1 { let uu = route[i - 1]; let vv = route[i + 1]; if uu == u && vv == v { idx = i; break; } } route.remove(idx); } else { commets_arround_stations[si].push((u, v)); } } else { let mut i = xorshift.next(route.len() - 1); let mut j = xorshift.next(route.len() - 1); if i == j { continue; } if i > j { std::mem::swap(&mut i, &mut j); } let mut next_sum_energies = sum_energies; let i_from = route[i]; let i_to = route[i + 1]; let j_from = route[j]; let j_to = route[j + 1]; if is_station(i_from) && is_station(j_from) || is_station(i_to) && is_station(j_to) { continue; } let (xi_from, yi_from) = if is_station(i_from) { stations[i_from - NUM_COMMETS] } else { commets[i_from] }; let (xi_to, yi_to) = if is_station(i_to) { stations[i_to - NUM_COMMETS] } else { commets[i_to] }; let (xj_from, yj_from) = if is_station(j_from) { stations[j_from - NUM_COMMETS] } else { commets[j_from] }; let (xj_to, yj_to) = if is_station(j_to) { stations[j_to - NUM_COMMETS] } else { commets[j_to] }; let which = if is_station(i_from) || is_station(i_to) { 1 } else { 0 }; next_sum_energies -= get_energy(xi_from, yi_from, xi_to, yi_to, which); let which = if is_station(j_from) || is_station(j_to) { 1 } else { 0 }; next_sum_energies -= get_energy(xj_from, yj_from, xj_to, yj_to, which); let which = if is_station(i_from) || is_station(j_from) { 1 } else { 0 }; next_sum_energies += get_energy(xi_from, yi_from, xj_from, yj_from, which); let which = if is_station(i_to) || is_station(j_to) { 1 } else { 0 }; next_sum_energies += get_energy(xi_to, yi_to, xj_to, yj_to, which); if next_sum_energies <= sum_energies { sum_energies = next_sum_energies; route[i + 1..=j].reverse(); for si in 0..NUM_STATIONS { commets_arround_stations[si].clear(); } for idx in 1..route.len() - 1 { let x = route[idx]; if is_station(x) { let u = route[idx - 1]; let v = route[idx + 1]; let si = x - NUM_COMMETS; commets_arround_stations[si].push((u, v)); } } } } } let score = (1_000_000_000.0 / (1000.0 + (sum_energies as f64).sqrt())).round() as i32; debug!(score); print_output(&stations, &route); eprintln!("time_elapsed: {:.3}", get_time()); }