Submission #39071970
Source Code Expand
use std::{io::{BufReader, BufRead}, collections::VecDeque};
use proconio::{source::line::LineSource, input};
struct UnionFind {
n: usize,
par: Vec<i32>,
}
impl UnionFind {
fn new(n: usize) -> Self {
Self {
n,
par: vec![-1; n],
}
}
fn merge(&mut self, a: usize, b: usize) -> usize {
let mut x = self.leader(a);
let mut y = self.leader(b);
if -self.par[x] < -self.par[y] {
let tmp = x;
x = y;
y = tmp;
}
self.par[x] += self.par[y];
self.par[y] = x as i32;
return x;
}
fn leader(&mut self, a: usize) -> usize {
if self.par[a] < 0 {
a
} else {
self.par[a] = self.leader(self.par[a] as usize) as i32;
self.par[a] as usize
}
}
fn same(&mut self, a: usize, b: usize) -> bool {
self.leader(a) == self.leader(b)
}
}
enum Responce {
NotBroken,
Broken,
}
struct Field {
n: usize,
c: usize,
guess: Vec<Vec<i32>>,
is_broken: Vec<Vec<bool>>,
real: Vec<Vec<i32>>,
total_cost: usize,
}
impl Field {
fn new(n: usize, c: usize) -> Self {
Self {
n, c, guess: vec![vec![0; n]; n], is_broken: vec![vec![false; n]; n], real: vec![vec![0; n]; n], total_cost: 0,
}
}
fn guess_field<R: BufRead>(&mut self, sources: &Vec<(usize, usize)>, houses: &Vec<(usize, usize)>, line_source: &mut LineSource<R>) {
let mut checks = vec![];
for &(y, x) in sources {
self.guess[y][x] = self.destruct(y, x, true, line_source);
checks.push((y, x));
}
for &(y, x) in houses {
self.guess[y][x] = self.destruct(y, x, true, line_source);
checks.push((y, x));
}
let step = (10..self.n).step_by(20).collect::<Vec<_>>();
for &y in &step {
for &x in &step {
let arrowed_min_dist = 5;
let rejected_min_dist = 75;
// (st, step), arr, rej (500ケース)
// (20, 40) 0,INF -> 127,083,022
// (20, 40) 0,100 -> 127,083,022
// (20, 40) 0, 75 -> 126,357,772
// (20, 40) 0, 50 -> 130,935,014
// (20, 40) 0, 75 -> 126,357,772
// (20, 40) 5, 75 -> 126,296,780
// (20, 40) 10, 75 -> 126,302,599
// (20, 40) 15, 75 -> 126,393,567
// (20, 40) 30, 75 -> 128,001,262
// 最寄りのchecksとのマンハッタン距離の最小値が規定値以下ならサボる
let min_dist = checks.iter().map(|&(cy, cx)| (cy as i32 - y as i32).abs() + (cx as i32 - x as i32).abs()).min().unwrap();
if min_dist <= arrowed_min_dist {
continue;
}
// 一番近いhouses, sourcesが規定値以上離れてるならサボる
let near_house_dist = houses.iter().map(|&(cy, cx)| (cy as i32 - y as i32).abs() + (cx as i32 - x as i32).abs()).min().unwrap();
let near_source_dist = sources.iter().map(|&(cy, cx)| (cy as i32 - y as i32).abs() + (cx as i32 - x as i32).abs()).min().unwrap();
if near_house_dist >= rejected_min_dist && near_source_dist >= rejected_min_dist {
continue;
}
self.guess[y][x] = self.destruct(y, x, true, line_source);
checks.push((y, x));
}
}
for y in 0..self.n {
for x in 0..self.n {
if checks.iter().any(|&(cy, cx)| cy == y && cx == x) {
continue;
}
// 一番近いchecksの値を採用
let &(ny, nx) = checks.iter().min_by_key(|&&(cy, cx)| (cy as i32 - y as i32).abs() + (cx as i32 - x as i32).abs()).unwrap();
self.guess[y][x] = self.guess[ny][nx];
}
}
// ===================================
// for &y in &step {
// for &x in &step {
// self.guess[y][x] = self.destruct(y, x, true, line_source);
// }
// }
// for y in 0..self.n {
// for x in 0..self.n {
// let ny = *step.iter().min_by_key(|&&ny| (ny as i32 - y as i32).abs()).unwrap();
// let nx = *step.iter().min_by_key(|&&nx| (nx as i32 - x as i32).abs()).unwrap();
// self.guess[y][x] = self.guess[ny][nx];
// }
// }
for _ in 0..40 {
self.guess_flatten();
}
}
fn guess_flatten(&mut self) {
let mut guess = vec![vec![0; self.n]; self.n];
let dxy = vec![(-1, 0), (1, 0), (0, -1), (0, 1)];
for y in 0..self.n {
for x in 0..self.n {
let mut sum = 0;
let mut cnt = 0;
for &(dy, dx) in &dxy {
let ny = x as i32 + dy;
let nx = y as i32 + dx;
if nx < 0 || nx >= self.n as i32 || ny < 0 || ny >= self.n as i32 {
continue;
}
let ny = ny as usize;
let nx = nx as usize;
sum += self.guess[ny][nx];
cnt += 1;
}
guess[y][x] = sum / cnt as i32;
}
}
self.guess = guess;
}
fn query<R: BufRead>(&mut self, y: usize, x: usize, power: i32, line_source: &mut LineSource<R>) -> Responce {
if self.is_broken[y][x] {
return Responce::Broken;
}
self.real[y][x] += power;
self.total_cost += self.c + power as usize;
println!("{} {} {}", y, x, power);
input! {
from line_source,
res: usize,
}
match res {
0 => Responce::NotBroken,
1 => {
self.is_broken[y][x] = true;
Responce::Broken
},
2 => {
std::process::exit(0);
},
_ => {
println!("# Error: Invalid responce.");
std::process::exit(1);
},
}
}
fn destruct<R: BufRead>(&mut self, y: usize, x: usize, guess: bool, line_source: &mut LineSource<R>) -> i32 {
if self.is_broken[y][x] {
return self.real[y][x];
}
if guess || !guess {
// 指標
let v = vec![0, 25, 60, 120, 210, 350, 570, 960, 1600, 2800, 5000];
for i in 0..v.len() - 1 {
self.query(y, x, v[i + 1] - v[i], line_source);
}
return self.real[y][x]
}
// let dxy = vec![(-1, 0), (1, 0), (0, -1), (0, 1)];
// for &(dy, dx) in &dxy {
// let ny = y as i32 + dy;
// let nx = x as i32 + dx;
// if nx < 0 || ny < 0 || nx >= self.n as i32 || ny >= self.n as i32 {
// continue;
// }
// if !self.is_broken[ny as usize][nx as usize] {
// continue;
// }
// let ny = ny as usize;
// let nx = nx as usize;
// let power = std::cmp::min(5000, self.real[ny][nx] - 400);
// let power = std::cmp::max(power, std::cmp::max(100, self.c * 5) as i32);
// self.query(y, x, power, line_source);
// break;
// }
// let power = if guess {
// if self.c >= 64 { 1000 } else { 500 }
// } else {
// // std::cmp::max(200, self.c * 5) as i32
// match self.c {
// 1 => 70,
// 2 => 100,
// 4 => 139,
// 8 => 200,
// 16 => 278,
// 32 => 385,
// 64 => 556,
// 128 => 833,
// _ => 1000,
// }
// };
// todo: 周辺リアル値と平均をとる
// guess値そのまま
// 500/500
// total: 132019032
// max: (1135380, '0449')
// ave: 264038.064
// min: (18100, '0347')
let power = (self.guess[y][x] as f64 * 0.9) as i32;
self.query(y, x, power, line_source);
let power = match self.c {
1 => 70,
2 => 100,
4 => 139,
8 => 200,
16 => 278,
32 => 385,
64 => 556,
128 => 833,
_ => 1000,
};
loop {
match self.query(y, x, power, line_source) {
Responce::NotBroken => (),
Responce::Broken => {
return self.real[y][x];
},
}
}
}
}
struct State {
sources: Vec<(usize, usize)>,
houses: Vec<(usize, usize)>,
destuctive: Vec<Vec<bool>>,
}
impl State {
fn new(sources: &Vec<(usize, usize)>, houses: &Vec<(usize, usize)>, field: &Field) -> Self {
Self {
sources: sources.clone(),
houses: houses.clone(),
destuctive: vec![vec![false; field.n]; field.n],
}
}
fn init_state(&mut self, field: &Field) {
let mut nodes = vec![];
for (i, &house) in (0_usize..).zip(&self.houses) {
nodes.push((house, i));
}
for (i, &source) in (0_usize..).zip(&self.sources) {
nodes.push((source, i + self.houses.len()));
}
let mut edges = vec![];
for &(u, u_id) in &nodes {
for &(v, v_id) in &nodes {
if u_id == v_id {
continue;
}
let (dist, path) = self.dijkstra(field, u, v);
edges.push((dist, u_id, v_id, path));
}
}
edges.sort_by(|a, b| a.0.cmp(&b.0));
println!("# init_state edges created: {}", edges.len());
let mut uf = UnionFind::new(self.houses.len() + self.sources.len());
let mut break_pos = vec![];
for (_, u_id, v_id, path) in &edges {
let u_id = *u_id;
let v_id = *v_id;
if uf.same(u_id, v_id) {
continue;
}
let u_has_water = (0..self.sources.len()).any(|i| uf.same(u_id, i + self.houses.len()));
let v_has_water = (0..self.sources.len()).any(|i| uf.same(v_id, i + self.houses.len()));
if !u_has_water || !v_has_water {
uf.merge(u_id, v_id);
for &(y, x) in path {
break_pos.push((y, x));
}
}
}
for &(y, x) in &break_pos {
self.destuctive[y][x] = true;
}
}
fn dijkstra(&self, field: &Field, s: (usize, usize), t: (usize, usize)) -> (i32, Vec<(usize, usize)>) {
println!("# dijkstra start");
let (sy, sx) = s;
let (ty, tx) = t;
let mut dist = vec![vec![std::i32::MAX; field.n]; field.n];
let mut que = std::collections::BinaryHeap::new();
que.push(std::cmp::Reverse((0, (sy, sx))));
dist[sy][sx] = 0;
let dyx = vec![(-1, 0), (1, 0), (0, -1), (0, 1)];
let cost = |y: usize, x: usize| {
field.guess[y][x]
};
while let Some(std::cmp::Reverse((d, (y, x)))) = que.pop() {
if y == ty && x == tx {
break;
}
if d > dist[y][x] {
continue;
}
for &(dy, dx) in &dyx {
let ny = y as i32 + dy;
let nx = x as i32 + dx;
if ny < 0 || nx < 0 || ny >= field.n as i32 || nx >= field.n as i32 {
continue;
}
let ny = ny as usize;
let nx = nx as usize;
let c = cost(ny, nx);
if dist[ny][nx] <= d + c {
continue;
}
dist[ny][nx] = d + c;
que.push(std::cmp::Reverse((d + c, (ny, nx))));
}
}
println!("# dijkstra path start");
// 復元
let mut res = vec![(ty, tx)];
loop {
let &(y, x) = res.last().unwrap();
if dist[y][x] == 0 {
break;
}
if y == sy && x == sx {
break;
}
// println!("# dist: {}, pos: {}, {}, cost: {}", dist[y][x], y, x, cost(y, x));
for &(dy, dx) in &dyx {
let py = y as i32 + dy;
let px = x as i32 + dx;
if py < 0 || px < 0 || py >= field.n as i32 || px >= field.n as i32 {
continue;
}
let py = py as usize;
let px = px as usize;
// println!("# >> dist: {}, pos: {}, {}", dist[py][px], py, px);
if dist[y][x] == dist[py][px] + cost(y, x) {
res.push((py, px));
break;
}
}
}
println!("# dijkstra finish");
return (dist[ty][tx], res);
}
fn done<R: BufRead>(&self, field: &mut Field, line_source: &mut LineSource<R>) {
for y in 0..field.n {
for x in 0..field.n {
if !self.destuctive[y][x] {
continue;
}
field.destruct(y, x, false, line_source);
}
}
}
}
struct Solver {
n: usize,
w: usize,
k: usize,
c: usize,
sources: Vec<(usize, usize)>,
houses: Vec<(usize, usize)>,
field: Field,
}
impl Solver {
fn new<R: BufRead>(line_source: &mut LineSource<R>) -> Self {
input! {
from line_source,
n: usize,
w: usize,
k: usize,
c: usize,
sources: [(usize, usize); w],
houses: [(usize, usize); k],
}
Self {
n, w, k, c, sources, houses, field: Field::new(n, c),
}
}
fn solve<R: BufRead>(&mut self, line_source: &mut LineSource<R>) {
// field init
self.field.guess_field(&self.sources, &self.houses, line_source);
println!("# field init done");
// init state
let mut state = State::new(&self.sources, &self.houses, &self.field);
state.init_state(&self.field);
println!("# state init done");
state.done(&mut self.field, line_source);
}
}
fn main() {
let stdin = std::io::stdin();
let mut line_source = LineSource::new(BufReader::new(stdin.lock()));
let mut solver = Solver::new(&mut line_source);
solver.solve(&mut line_source);
}
Submission Info
| Submission Time |
|
| Task |
A - Excavation |
| User |
Kyo_s_s |
| Language |
Rust (1.42.0) |
| Score |
10564394 |
| Code Size |
15212 Byte |
| Status |
AC |
| Exec Time |
344 ms |
| Memory |
3872 KiB |
Compile Error
warning: unused import: `collections::VecDeque`
--> src/main.rs:1:37
|
1 | use std::{io::{BufReader, BufRead}, collections::VecDeque};
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: field is never read: `n`
--> src/main.rs:6:5
|
6 | n: usize,
| ^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: field is never read: `n`
--> src/main.rs:410:5
|
410 | n: usize,
| ^^^^^^^^
warning: field is never read: `w`
--> src/main.rs:411:5
|
411 | w: usize,
| ^^^^^^^^
warning: field is never read: `k`
--> src/main.rs:412:5
|
412 | k: usize,
| ^^^^^^^^
warning: field is never read: `c`
--> src/main.rs:413:5
|
413 | c: usize,
| ^^^^^^^^
Judge Result
| Set Name |
test_ALL |
| Score / Max Score |
10564394 / 50000000000 |
| Status |
|
| Set Name |
Test Cases |
| 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 |
| Case Name |
Status |
Exec Time |
Memory |
| test_0000.txt |
AC |
196 ms |
3808 KiB |
| test_0001.txt |
AC |
85 ms |
3704 KiB |
| test_0002.txt |
AC |
240 ms |
3648 KiB |
| test_0003.txt |
AC |
92 ms |
3644 KiB |
| test_0004.txt |
AC |
256 ms |
3644 KiB |
| test_0005.txt |
AC |
318 ms |
3696 KiB |
| test_0006.txt |
AC |
103 ms |
3756 KiB |
| test_0007.txt |
AC |
225 ms |
3700 KiB |
| test_0008.txt |
AC |
260 ms |
3644 KiB |
| test_0009.txt |
AC |
268 ms |
3772 KiB |
| test_0010.txt |
AC |
155 ms |
3752 KiB |
| test_0011.txt |
AC |
136 ms |
3744 KiB |
| test_0012.txt |
AC |
205 ms |
3688 KiB |
| test_0013.txt |
AC |
266 ms |
3680 KiB |
| test_0014.txt |
AC |
344 ms |
3872 KiB |
| test_0015.txt |
AC |
170 ms |
3684 KiB |
| test_0016.txt |
AC |
91 ms |
3704 KiB |
| test_0017.txt |
AC |
83 ms |
3644 KiB |
| test_0018.txt |
AC |
69 ms |
3760 KiB |
| test_0019.txt |
AC |
317 ms |
3648 KiB |
| test_0020.txt |
AC |
303 ms |
3744 KiB |
| test_0021.txt |
AC |
109 ms |
3684 KiB |
| test_0022.txt |
AC |
222 ms |
3740 KiB |
| test_0023.txt |
AC |
134 ms |
3768 KiB |
| test_0024.txt |
AC |
236 ms |
3700 KiB |
| test_0025.txt |
AC |
98 ms |
3764 KiB |
| test_0026.txt |
AC |
207 ms |
3764 KiB |
| test_0027.txt |
AC |
66 ms |
3760 KiB |
| test_0028.txt |
AC |
93 ms |
3752 KiB |
| test_0029.txt |
AC |
159 ms |
3808 KiB |
| test_0030.txt |
AC |
120 ms |
3800 KiB |
| test_0031.txt |
AC |
79 ms |
3812 KiB |
| test_0032.txt |
AC |
265 ms |
3704 KiB |
| test_0033.txt |
AC |
129 ms |
3692 KiB |
| test_0034.txt |
AC |
176 ms |
3804 KiB |
| test_0035.txt |
AC |
79 ms |
3776 KiB |
| test_0036.txt |
AC |
226 ms |
3744 KiB |
| test_0037.txt |
AC |
132 ms |
3748 KiB |
| test_0038.txt |
AC |
254 ms |
3812 KiB |
| test_0039.txt |
AC |
250 ms |
3684 KiB |
| test_0040.txt |
AC |
104 ms |
3700 KiB |
| test_0041.txt |
AC |
135 ms |
3832 KiB |
| test_0042.txt |
AC |
252 ms |
3740 KiB |
| test_0043.txt |
AC |
87 ms |
3812 KiB |
| test_0044.txt |
AC |
111 ms |
3688 KiB |
| test_0045.txt |
AC |
70 ms |
3808 KiB |
| test_0046.txt |
AC |
129 ms |
3644 KiB |
| test_0047.txt |
AC |
301 ms |
3804 KiB |
| test_0048.txt |
AC |
297 ms |
3680 KiB |
| test_0049.txt |
AC |
85 ms |
3624 KiB |