Submission #39074311


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;
                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 {
                    checks.push((y, x));
                    self.guess[y][x] = 4500;
                    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 _ 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];
        }

        let v = match self.c {
              1 => vec![0, 15, 25, 40, 65, 95, 140, 190, 250, 330, 415, 520, 650, 840, 1075, 1400, 1750, 2270, 2875, 3550, 5000],
              2 => vec![0, 15, 25, 40, 65, 95, 140, 190, 250, 330, 415, 520, 650, 840, 1075, 1400, 1750, 2270, 2875, 3550, 5000],
              4 => vec![0, 15, 25, 40, 65, 95, 140, 190, 250, 330, 415, 520, 650, 840, 1075, 1400, 1750, 2270, 2875, 3550, 5000],
              8 => vec![0, 15, 25, 40, 65, 95, 140, 190, 250, 330, 415, 520, 650, 840, 1075, 1400, 1750, 2270, 2875, 3550, 5000],
             16 => vec![0, 20, 40, 70, 120, 190, 280, 395, 540, 760, 1080, 1515, 2160, 3000, 5000],
             32 => vec![0, 20, 40, 70, 120, 190, 280, 395, 540, 760, 1080, 1515, 2160, 3000, 5000],
             64 => vec![0, 25, 60, 120, 210, 350, 570, 960, 1600, 2800, 5000],
            128 => vec![0, 30, 90, 220, 410, 730, 1370, 2560, 5000],
            _ => vec![0, 25, 60, 120, 210, 350, 570, 960, 1600, 2800, 5000],
        };
        if guess {
            // 最後サボる
            for i in 0..v.len() - 1 {
                if v[i + 1] >= 2000 {
                    break;
                }
                self.query(y, x, v[i + 1] - v[i], line_source);
            }
            if self.is_broken[y][x] {
                return self.real[y][x];
            } 
            return 4500
        } 

        // 隣接マスにrealが有効なものがある -> その値を叩く   
        let dxy = vec![(-1, 0), (1, 0), (0, -1), (0, 1)];
        let mut i = 0;
        for &(dy, dx) in &(dxy) {
            let ny = y as i32 + dy;
            let nx = x 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;
            if !self.is_broken[ny][nx] {
                continue;
            } 
            // self.real[ny][nx] を越える最大のv[i]を探す
            while i < v.len() - 1 && v[i + 1] <= self.real[ny][nx] {
                i += 1;
            }
            if i > 1 {
                i = (i as i32 - 1) as usize;
            }
            self.query(y, x, v[i], line_source);
            break;
        }
        for i in i..v.len() - 1 {
            self.query(y, x, v[i + 1] - v[i], line_source);
        }
        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 7933536
Code Size 14078 Byte
Status AC
Exec Time 351 ms
Memory 3856 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:365:5
    |
365 |     n: usize,
    |     ^^^^^^^^

warning: field is never read: `w`
   --> src/main.rs:366:5
    |
366 |     w: usize,
    |     ^^^^^^^^

warning: field is never read: `k`
   --> src/main.rs:367:5
    |
367 |     k: usize,
    |     ^^^^^^^^

warning: field is never read: `c`
   --> src/main.rs:368:5
    |
368 |     c: usize,
    |     ^^^^^^^^

Judge Result

Set Name test_ALL
Score / Max Score 7933536 / 50000000000
Status
AC × 50
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 191 ms 3792 KiB
test_0001.txt AC 76 ms 3780 KiB
test_0002.txt AC 230 ms 3760 KiB
test_0003.txt AC 86 ms 3680 KiB
test_0004.txt AC 258 ms 3820 KiB
test_0005.txt AC 331 ms 3732 KiB
test_0006.txt AC 102 ms 3680 KiB
test_0007.txt AC 228 ms 3688 KiB
test_0008.txt AC 250 ms 3684 KiB
test_0009.txt AC 276 ms 3688 KiB
test_0010.txt AC 160 ms 3796 KiB
test_0011.txt AC 128 ms 3780 KiB
test_0012.txt AC 207 ms 3736 KiB
test_0013.txt AC 278 ms 3732 KiB
test_0014.txt AC 351 ms 3856 KiB
test_0015.txt AC 141 ms 3796 KiB
test_0016.txt AC 86 ms 3680 KiB
test_0017.txt AC 76 ms 3796 KiB
test_0018.txt AC 71 ms 3820 KiB
test_0019.txt AC 326 ms 3672 KiB
test_0020.txt AC 309 ms 3688 KiB
test_0021.txt AC 110 ms 3672 KiB
test_0022.txt AC 229 ms 3744 KiB
test_0023.txt AC 131 ms 3796 KiB
test_0024.txt AC 229 ms 3800 KiB
test_0025.txt AC 96 ms 3796 KiB
test_0026.txt AC 191 ms 3820 KiB
test_0027.txt AC 67 ms 3796 KiB
test_0028.txt AC 86 ms 3792 KiB
test_0029.txt AC 156 ms 3744 KiB
test_0030.txt AC 108 ms 3692 KiB
test_0031.txt AC 79 ms 3804 KiB
test_0032.txt AC 265 ms 3828 KiB
test_0033.txt AC 126 ms 3688 KiB
test_0034.txt AC 169 ms 3692 KiB
test_0035.txt AC 78 ms 3688 KiB
test_0036.txt AC 206 ms 3740 KiB
test_0037.txt AC 130 ms 3636 KiB
test_0038.txt AC 251 ms 3732 KiB
test_0039.txt AC 255 ms 3632 KiB
test_0040.txt AC 96 ms 3680 KiB
test_0041.txt AC 125 ms 3792 KiB
test_0042.txt AC 254 ms 3744 KiB
test_0043.txt AC 79 ms 3760 KiB
test_0044.txt AC 111 ms 3756 KiB
test_0045.txt AC 60 ms 3712 KiB
test_0046.txt AC 119 ms 3676 KiB
test_0047.txt AC 319 ms 3672 KiB
test_0048.txt AC 266 ms 3732 KiB
test_0049.txt AC 81 ms 3688 KiB