提出 #27915835


ソースコード 拡げる

#![allow(non_snake_case, unused)]

use proconio::{*, marker::*, source::line::LineSource};
use rand::prelude::*;
use std::io::{BufReader, Stdin};

pub trait SetMinMax {
	fn setmin(&mut self, v: Self) -> bool;
	fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T where T: PartialOrd {
	fn setmin(&mut self, v: T) -> bool {
		*self > v && { *self = v; true }
	}
	fn setmax(&mut self, v: T) -> bool {
		*self < v && { *self = v; true }
	}
}

#[macro_export]
macro_rules! mat {
	($($e:expr),*) => { Vec::from(vec![$($e),*]) };
	($($e:expr,)*) => { Vec::from(vec![$($e),*]) };
	($e:expr; $d:expr) => { Vec::from(vec![$e; $d]) };
	($e:expr; $d:expr $(; $ds:expr)+) => { Vec::from(vec![mat![$e $(; $ds)*]; $d]) };
}

pub 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
	}
}

use std::cell::Cell;
use std::collections::BinaryHeap;

#[derive(Clone, Debug)]
pub struct UnionFind {
	/// size / parent
	ps: Vec<Cell<usize>>,
	pub is_root: Vec<bool>
}

impl UnionFind {
	pub fn new(n: usize) -> UnionFind {
		UnionFind { ps: vec![Cell::new(1); n], is_root: vec![true; n] }
	}
	pub fn find(&self, x: usize) -> usize {
		if self.is_root[x] { x }
		else {
			let p = self.find(self.ps[x].get());
			self.ps[x].set(p);
			p
		}
	}
	pub fn unite(&mut self, x: usize, y: usize) {
		let mut x = self.find(x);
		let mut y = self.find(y);
		if x == y { return }
		if self.ps[x].get() < self.ps[y].get() {
			::std::mem::swap(&mut x, &mut y);
		}
		*self.ps[x].get_mut() += self.ps[y].get();
		self.ps[y].set(x);
		self.is_root[y] = false;
	}
	pub fn same(&self, x: usize, y: usize) -> bool {
		self.find(x) == self.find(y)
	}
	pub fn size(&self, x: usize) -> usize {
		self.ps[self.find(x)].get()
	}
}

const K: usize = 5;
pub const N: usize = 400;
pub const M: usize = (N - 1) * K;

pub struct Input {
	ps: Vec<(i32, i32)>,
	es: Vec<(usize, usize, i32, i32)>
}

fn dist2((x1, y1): (i32, i32), (x2, y2): (i32, i32)) -> i32 {
	(x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)
}

fn dist(p1: (i32, i32), p2: (i32, i32)) -> i32 {
	f64::sqrt(dist2(p1, p2) as f64).round() as i32
}

fn read_input(stdin: &mut LineSource<BufReader<Stdin>>) -> Input {
	input! {
		from stdin,
		ps: [(i32, i32); N],
		es: [(usize, usize); M],
	}
	let es = es.into_iter().map(|(u, v)| {
		let d = dist(ps[u], ps[v]);
		(u, v, d, d * 3)
	}).collect();
	Input {
		ps,
		es,
	}
}

// 与えられた辺集合から1本選ぶ場合の長さの期待値をDPで最小化してcを選ぶ方が良いか判定
fn dp2(input: &Input, cut: &Vec<usize>, c: i32) -> bool {
	let n = cut.len();
	let mut dp = vec![0.0; n];
	dp[n - 1] = (input.es[cut[n - 1]].2 + input.es[cut[n - 1]].3) as f64 / 2.0;
	for k in (0..n-1).rev() {
		let L = input.es[cut[k]].2 as f64;
		let R = input.es[cut[k]].3 as f64;
		if dp[k + 1] <= L {
			dp[k] = dp[k + 1];
		} else if R <= dp[k + 1] {
			dp[k] = (L + R) / 2.0;
		} else {
			let p = dp[k + 1].floor();
			dp[k] = ((L + p) * (p - L + 1.0) / 2.0 + dp[k + 1] * (R - p)) / (R - L + 1.0);
		}
	}
	c as f64 <= dp[1]
}

// 与えられた3種類の辺集合から異なる種類の2辺を選ぶ場合の長さの期待値をDPで最小化してcを選ぶ方が良いか判定
fn dp3(input: &Input, cut: &Vec<(usize, i32)>, c: i32) -> bool {
	let n = cut.len();
	let mut dp = mat![0.0f64; n + 1; 8];
	for i in 0..8 {
		if usize::count_ones(i) >= 2 {
			dp[n][i] = 1e9;
		}
	}
	for k in (0..n).rev() {
		let (e, p) = cut[k];
		for i in 0..8 {
			if i >> p & 1 != 0 {
				let i2 = i ^ (1 << p);
				let L = dp[k + 1][i2] + input.es[e].2 as f64;
				let R = dp[k + 1][i2] + input.es[e].3 as f64;
				if dp[k + 1][i] <= L {
					dp[k][i] = dp[k + 1][i];
				} else if R <= dp[k + 1][i] {
					dp[k][i] = (L + R) / 2.0;
				} else {
					let p = dp[k + 1][i].floor();
					dp[k][i] = ((L + p) * (p - L + 1.0) / 2.0 + dp[k + 1][i] * (R - p)) / (R - L + 1.0);
				}
			} else {
				dp[k][i] = dp[k + 1][i];
			}
		}
	}
	dp[0][7 ^ (1 << cut[0].1)] + c as f64 <= dp[1][7]
}

const REP: usize = 1000;

// DPで判定に失敗したときだけモンテカルロ

fn solve(input: &Input, mut stdin: LineSource<BufReader<Stdin>>) {
	let mut rng = rand_pcg::Pcg64Mcg::seed_from_u64(8391028707);
	let mut es = mat![(0, 0, 0, 0); REP; M];
	for i in 0..REP {
		for e in 0..M {
			es[i][e] = (rng.gen_range(input.es[e].2 * 113 / 100, input.es[e].3 - input.es[e].2 * 13 / 100 + 1), e, input.es[e].0, input.es[e].1);
		}
		es[i].sort();
	}
	let mut uf = UnionFind::new(N);
	let mut out = vec![0; M];
	let mut cost = 0;
	for f in 0..M {
		input! {
			from &mut stdin,
			c: i32,
		}
		let (s, t, _, _) = input.es[f];
		if !uf.same(s, t) {
			let mut uf2 = uf.clone();
			for e in f+1..M {
				// 期待値の小さい辺がカットに含まれると判定に失敗するので先に縮約 (3-way cutでの判定時に確実に失敗する条件はよく分からないのでちょっと余裕を持たせた)
				if (input.es[e].2 + input.es[e].3) as f64 / 2.0 + 10.0 < c as f64 {
					uf2.unite(input.es[e].0, input.es[e].1);
				}
			}
			if !uf2.same(s, t) {
				// 高速化のため、縮約後のグラフを構築
				let mut id = vec![!0; N];
				let mut m = 0;
				for i in 0..N {
					if id[uf2.find(i)] == !0 {
						id[uf2.find(i)] = m;
						m += 1;
					}
					id[i] = id[uf2.find(i)];
				}
				eprintln!("{}: {}", f, m);
				let mut g = vec![vec![]; N];
				for e in f..M {
					let i = id[input.es[e].0];
					let j = id[input.es[e].1];
					if i != j {
						g[i].push((j, e));
						g[j].push((i, e));
					}
				}
				let (s, t) = (id[s], id[t]);
				for iter in 0..50 {
					// ランダム重みでprim法を走らせてカットを構築
					let mut que = BinaryHeap::new();
					let mut min = vec![(1000000000, -1i32); m];
					let mut fixed = vec![false; m];
					let mut cut = vec![vec![]; 2];
					let mut tmp = vec![];
					que.push((0, s));
					que.push((0, t));
					min[s] = (0, 0);
					min[t] = (0, 1);
					while let Some((_, u)) = que.pop() {
						if fixed[u] {
							continue;
						}
						fixed[u] = true;
						let r = min[u].1;
						{ // 2-way cut での判定
							let cut = &mut cut[r as usize];
							tmp.clear();
							let mut x = 0;
							let mut y = 0;
							while x < cut.len() && y < g[u].len() {
								if cut[x] == g[u][y].1 {
									x += 1;
									y += 1;
								} else if cut[x] < g[u][y].1 {
									tmp.push(cut[x]);
									x += 1;
								} else {
									tmp.push(g[u][y].1);
									y += 1;
								}
							}
							while x < cut.len() {
								tmp.push(cut[x]);
								x += 1;
							}
							while y < g[u].len() {
								tmp.push(g[u][y].1);
								y += 1;
							}
							std::mem::swap(cut, &mut tmp);
							let cut0 = cut.iter().filter(|&&e| fixed[id[input.es[e].0]] && fixed[id[input.es[e].1]]).cloned().collect::<Vec<_>>();
							if cut0.len() >= 2 && !dp2(input, &cut0, c) { // この先ずっとカットに含まれる辺のみで判定に失敗したら枝刈り
								break;
							}
							if cut.len() == 1 || dp2(input, &cut, c) { // cutから1本以上選ぶ必要が有り、現在の辺を選ばなかった場合の期待値の方が大きいなら選んだ方がお得
								out[f] = 1;
								break;
							}
						}
						if cut[0].len() > 0 && cut[1].len() > 0 { // 3-way cut での判定
							let mut cut2 = vec![];
							let mut x = 0;
							let mut y = 0;
							while x < cut[0].len() && y < cut[1].len() {
								if cut[0][x] == cut[1][y] {
									cut2.push((cut[0][x], 0));
									x += 1;
									y += 1;
								} else if cut[0][x] < cut[1][y] {
									cut2.push((cut[0][x], 1));
									x += 1;
								} else {
									cut2.push((cut[1][y], 2));
									y += 1;
								}
							}
							while x < cut[0].len() {
								cut2.push((cut[0][x], 1));
								x += 1;
							}
							while y < cut[1].len() {
								cut2.push((cut[1][y], 2));
								y += 1;
							}
							if dp3(input, &cut2, c) { // cutから2本以上選ぶ必要が有り、現在の辺を選ばなかった場合の期待値の方が大きいなら選んだ方がお得
								out[f] = 1;
								eprintln!("3-way cut");
								break;
							}
						}
						for &(v, e) in &g[u] {
							if fixed[v] {
								continue;
							}
							let d = rng.gen_range(input.es[e].2, input.es[e].3 + 1);
							if min[v].0 > d {
								min[v] = (d, r);
								que.push((-d, v));
							}
						}
					}
					if out[f] == 1 {
						break;
					}
				}
			}
			if out[f] == 0 {
				let (s, t) = (uf.find(input.es[f].0), uf.find(input.es[f].1));
				let mut avg = 0;
				for i in 0..REP {
					let mut uf2 = uf.clone();
					for &(d, e, u, v) in &es[i] {
						if e > f && !uf2.same(u, v) {
							uf2.unite(u, v);
							if uf2.same(s, t) {
								avg += d - c;
								break;
							}
						}
					}
					if !uf2.same(s, t) {
						avg = 1000000000;
						break;
					}
					if avg.abs() > 1000 {
						break;
					}
				}
				if avg >= 0 {
					out[f] = 1;
				}
			}
		}
		if out[f] == 1 {
			uf.unite(s, t);
			cost += c;
		}
		println!("{}", out[f]);
	}
	eprintln!("cost = {}", cost);
	assert_eq!(out.iter().sum::<usize>(), N - 1);
}

fn main() {
	get_time();
	let mut stdin = proconio::source::line::LineSource::new(std::io::BufReader::new(std::io::stdin()));
	let input = read_input(&mut stdin);
	solve(&input, stdin);
	eprintln!("Time = {:.3}", get_time());
}

提出情報

提出日時
問題 A - Online MST
ユーザ wata_admin
言語 Rust (1.42.0)
得点 14255644618
コード長 9907 Byte
結果 AC
実行時間 1823 ms
メモリ 65504 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 14255644618 / 10000000
結果
AC × 150
セット名 テストケース
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
ケース名 結果 実行時間 メモリ
test_0000.txt AC 1423 ms 65492 KiB
test_0001.txt AC 1398 ms 65456 KiB
test_0002.txt AC 1211 ms 65344 KiB
test_0003.txt AC 1371 ms 65372 KiB
test_0004.txt AC 1523 ms 65440 KiB
test_0005.txt AC 1562 ms 65324 KiB
test_0006.txt AC 1559 ms 65360 KiB
test_0007.txt AC 1082 ms 65348 KiB
test_0008.txt AC 1386 ms 65288 KiB
test_0009.txt AC 1232 ms 65424 KiB
test_0010.txt AC 1412 ms 65392 KiB
test_0011.txt AC 1334 ms 65420 KiB
test_0012.txt AC 1470 ms 65364 KiB
test_0013.txt AC 1495 ms 65328 KiB
test_0014.txt AC 1802 ms 65276 KiB
test_0015.txt AC 1075 ms 65348 KiB
test_0016.txt AC 1179 ms 65344 KiB
test_0017.txt AC 1398 ms 65352 KiB
test_0018.txt AC 1391 ms 65408 KiB
test_0019.txt AC 1452 ms 65412 KiB
test_0020.txt AC 1656 ms 65432 KiB
test_0021.txt AC 1659 ms 65412 KiB
test_0022.txt AC 1325 ms 65468 KiB
test_0023.txt AC 1601 ms 65412 KiB
test_0024.txt AC 1122 ms 65492 KiB
test_0025.txt AC 1261 ms 65492 KiB
test_0026.txt AC 1269 ms 65300 KiB
test_0027.txt AC 1279 ms 65420 KiB
test_0028.txt AC 1396 ms 65376 KiB
test_0029.txt AC 1300 ms 65480 KiB
test_0030.txt AC 1244 ms 65452 KiB
test_0031.txt AC 1371 ms 65408 KiB
test_0032.txt AC 1596 ms 65348 KiB
test_0033.txt AC 1354 ms 65500 KiB
test_0034.txt AC 1465 ms 65220 KiB
test_0035.txt AC 1536 ms 65368 KiB
test_0036.txt AC 1585 ms 65352 KiB
test_0037.txt AC 1268 ms 65308 KiB
test_0038.txt AC 1430 ms 65412 KiB
test_0039.txt AC 1566 ms 65332 KiB
test_0040.txt AC 1578 ms 65452 KiB
test_0041.txt AC 1378 ms 65452 KiB
test_0042.txt AC 1252 ms 65376 KiB
test_0043.txt AC 1186 ms 65404 KiB
test_0044.txt AC 1506 ms 65476 KiB
test_0045.txt AC 1115 ms 65372 KiB
test_0046.txt AC 1070 ms 65368 KiB
test_0047.txt AC 1515 ms 65348 KiB
test_0048.txt AC 1207 ms 65352 KiB
test_0049.txt AC 1124 ms 65352 KiB
test_0050.txt AC 1498 ms 65500 KiB
test_0051.txt AC 1372 ms 65328 KiB
test_0052.txt AC 1139 ms 65352 KiB
test_0053.txt AC 1169 ms 65368 KiB
test_0054.txt AC 1201 ms 65456 KiB
test_0055.txt AC 1387 ms 65416 KiB
test_0056.txt AC 1377 ms 65316 KiB
test_0057.txt AC 1688 ms 65408 KiB
test_0058.txt AC 1356 ms 65456 KiB
test_0059.txt AC 1549 ms 65352 KiB
test_0060.txt AC 1349 ms 65332 KiB
test_0061.txt AC 1447 ms 65440 KiB
test_0062.txt AC 1422 ms 65464 KiB
test_0063.txt AC 1759 ms 65492 KiB
test_0064.txt AC 1212 ms 65456 KiB
test_0065.txt AC 1344 ms 65416 KiB
test_0066.txt AC 1584 ms 65276 KiB
test_0067.txt AC 1156 ms 65296 KiB
test_0068.txt AC 1309 ms 65484 KiB
test_0069.txt AC 1741 ms 65432 KiB
test_0070.txt AC 1483 ms 65400 KiB
test_0071.txt AC 1679 ms 65400 KiB
test_0072.txt AC 1373 ms 65304 KiB
test_0073.txt AC 1430 ms 65268 KiB
test_0074.txt AC 1210 ms 65380 KiB
test_0075.txt AC 1413 ms 65376 KiB
test_0076.txt AC 1252 ms 65436 KiB
test_0077.txt AC 1496 ms 65376 KiB
test_0078.txt AC 1305 ms 65336 KiB
test_0079.txt AC 1265 ms 65312 KiB
test_0080.txt AC 1457 ms 65452 KiB
test_0081.txt AC 1343 ms 65360 KiB
test_0082.txt AC 1308 ms 65504 KiB
test_0083.txt AC 1260 ms 65320 KiB
test_0084.txt AC 1432 ms 65356 KiB
test_0085.txt AC 1094 ms 65308 KiB
test_0086.txt AC 1460 ms 65344 KiB
test_0087.txt AC 1216 ms 65428 KiB
test_0088.txt AC 1422 ms 65348 KiB
test_0089.txt AC 1374 ms 65268 KiB
test_0090.txt AC 1569 ms 65472 KiB
test_0091.txt AC 1372 ms 65300 KiB
test_0092.txt AC 1463 ms 65488 KiB
test_0093.txt AC 1322 ms 65376 KiB
test_0094.txt AC 1123 ms 65324 KiB
test_0095.txt AC 1541 ms 65412 KiB
test_0096.txt AC 1243 ms 65496 KiB
test_0097.txt AC 1234 ms 65232 KiB
test_0098.txt AC 1300 ms 65344 KiB
test_0099.txt AC 1375 ms 65496 KiB
test_0100.txt AC 1440 ms 65452 KiB
test_0101.txt AC 1310 ms 65424 KiB
test_0102.txt AC 1241 ms 65352 KiB
test_0103.txt AC 1477 ms 65504 KiB
test_0104.txt AC 1523 ms 65376 KiB
test_0105.txt AC 1350 ms 65392 KiB
test_0106.txt AC 1485 ms 65416 KiB
test_0107.txt AC 1823 ms 65372 KiB
test_0108.txt AC 1394 ms 65456 KiB
test_0109.txt AC 1489 ms 65364 KiB
test_0110.txt AC 1387 ms 65332 KiB
test_0111.txt AC 1363 ms 65428 KiB
test_0112.txt AC 1440 ms 65412 KiB
test_0113.txt AC 1498 ms 65448 KiB
test_0114.txt AC 1443 ms 65356 KiB
test_0115.txt AC 1504 ms 65504 KiB
test_0116.txt AC 1140 ms 65292 KiB
test_0117.txt AC 1256 ms 65420 KiB
test_0118.txt AC 1383 ms 65404 KiB
test_0119.txt AC 1253 ms 65320 KiB
test_0120.txt AC 1288 ms 65340 KiB
test_0121.txt AC 1204 ms 65332 KiB
test_0122.txt AC 1377 ms 65328 KiB
test_0123.txt AC 1344 ms 65424 KiB
test_0124.txt AC 1406 ms 65276 KiB
test_0125.txt AC 1214 ms 65316 KiB
test_0126.txt AC 1313 ms 65372 KiB
test_0127.txt AC 1571 ms 65348 KiB
test_0128.txt AC 1446 ms 65352 KiB
test_0129.txt AC 1420 ms 65360 KiB
test_0130.txt AC 1199 ms 65336 KiB
test_0131.txt AC 1409 ms 65364 KiB
test_0132.txt AC 1218 ms 65360 KiB
test_0133.txt AC 1347 ms 65424 KiB
test_0134.txt AC 1393 ms 65444 KiB
test_0135.txt AC 1375 ms 65368 KiB
test_0136.txt AC 1469 ms 65284 KiB
test_0137.txt AC 1329 ms 65348 KiB
test_0138.txt AC 1425 ms 65288 KiB
test_0139.txt AC 1346 ms 65492 KiB
test_0140.txt AC 1611 ms 65364 KiB
test_0141.txt AC 1440 ms 65352 KiB
test_0142.txt AC 1009 ms 65336 KiB
test_0143.txt AC 1445 ms 65320 KiB
test_0144.txt AC 1362 ms 65372 KiB
test_0145.txt AC 1710 ms 65436 KiB
test_0146.txt AC 1467 ms 65412 KiB
test_0147.txt AC 1385 ms 65452 KiB
test_0148.txt AC 1177 ms 65244 KiB
test_0149.txt AC 1256 ms 65460 KiB