結果

問題 No.5025 Forest Fire
コンテスト
ユーザー 👑 terry_u16
提出日時 2026-10-24 17:19:54
言語 Rust
(1.99.0 + proconio + num + itertools + ACL)
コンパイル:
/usr/bin/rustc_custom
実行:
./target/release/main
結果
AC  
実行時間 1,911 ms / 2,000 ms
+ 320µs
コード長 86,941 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 7,081 ms
コンパイル使用メモリ 214,540 KB
実行使用メモリ 9,920 KB
スコア 192,477,054
最終ジャッジ日時 2026-10-24 17:26:34
合計ジャッジ時間 165,146 ms
ジャッジサーバーID
(参考情報)
judge5_0 / <nil>
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 50
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

pub mod library {
    //! ヒューリスティック問題向けの共通ライブラリ。

    // annealing.rsは未使用で、yukicoderで利用できない外部クレートに依存するため公開しない。
    pub mod bitboard {
        use crate::library::grid::Coord;

        /// 一辺64マス以下の正方形グリッドを、1行1ワードで表すビット集合。
        #[derive(Debug, Clone, PartialEq, Eq)]
        pub struct BitBoard<const N: usize> {
            rows: [u64; N],
        }

        impl<const N: usize> Default for BitBoard<N> {
            fn default() -> Self {
                assert!(N > 0 && N <= 64);
                Self { rows: [0; N] }
            }
        }

        impl<const N: usize> BitBoard<N> {
            pub fn insert(&mut self, p: Coord) {
                debug_assert!(p.row() < N && p.col() < N);
                self.rows[p.row()] |= 1_u64 << p.col();
            }

            pub fn contains(&self, p: Coord) -> bool {
                debug_assert!(p.row() < N && p.col() < N);
                self.rows[p.row()] & (1_u64 << p.col()) != 0
            }

            /// この集合内だけを4近傍移動し、startから距離radius以下のマスを返す。
            /// 配列はスタック上に置き、毎段のヒープ確保・頂点キュー操作を避ける。
            pub fn within_distance(&self, start: Coord, radius: usize) -> Self {
                let mut reached = Self::default();
                if !self.contains(start) {
                    return reached;
                }
                reached.insert(start);
                let mut frontier = reached.rows;
                let mut first = start.row();
                let mut last = start.row();
                for _ in 0..radius {
                    first = first.saturating_sub(1);
                    last = (last + 1).min(N - 1);
                    let mut next = [0_u64; N];
                    let mut any = 0;
                    // radius段で到達し得る行だけを走査する。
                    for row in first..=last {
                        let mut adjacent = (frontier[row] << 1) | (frontier[row] >> 1);
                        if row > 0 {
                            adjacent |= frontier[row - 1];
                        }
                        if row + 1 < N {
                            adjacent |= frontier[row + 1];
                        }
                        // 成分外・行の右端より外・既訪問のビットを落とす。
                        let bits = adjacent & self.rows[row] & !reached.rows[row];
                        next[row] = bits;
                        reached.rows[row] |= bits;
                        any |= bits;
                    }
                    if any == 0 {
                        break;
                    }
                    frontier = next;
                }
                reached
            }
        }

        #[cfg(test)]
        mod tests {
            use super::*;
            use crate::library::{
                grid::{ADJACENTS, Map2d},
                random::Random,
            };

            fn queue_bfs<const N: usize>(
                board: &BitBoard<N>,
                start: Coord,
                radius: usize,
            ) -> BitBoard<N> {
                let mut reached = BitBoard::default();
                if !board.contains(start) {
                    return reached;
                }
                let mut distances = Map2d::from_fn(|_| usize::MAX, N);
                let mut queue = vec![start];
                distances[start] = 0;
                reached.insert(start);
                let mut head = 0;
                while head < queue.len() {
                    let p = queue[head];
                    head += 1;
                    if distances[p] == radius {
                        continue;
                    }
                    for diff in ADJACENTS {
                        let next = p + diff;
                        if next.in_map(N) && board.contains(next) && distances[next] == usize::MAX {
                            distances[next] = distances[p] + 1;
                            reached.insert(next);
                            queue.push(next);
                        }
                    }
                }
                reached
            }

            #[test]
            fn detour_uses_path_distance_not_manhattan_distance() {
                let mut board = BitBoard::<5>::default();
                for row in 0..5 {
                    board.insert(Coord::new(row, 0));
                    board.insert(Coord::new(row, 2));
                }
                board.insert(Coord::new(4, 1));
                let start = Coord::new(0, 0);
                let goal = Coord::new(0, 2);
                assert_eq!(start.dist(&goal), 2);
                assert!(!board.within_distance(start, 9).contains(goal));
                assert!(board.within_distance(start, 10).contains(goal));
            }

            #[test]
            fn random_and_full_boards_match_queue_bfs() {
                let mut rng = Random::new(123);
                for density in [0, 4, 7, 10] {
                    for _ in 0..8 {
                        let mut board = BitBoard::<50>::default();
                        for row in 0..50 {
                            for col in 0..50 {
                                if rng.index(10) < density {
                                    board.insert(Coord::new(row, col));
                                }
                            }
                        }
                        for start in [Coord::new(0, 0), Coord::new(49, 49), Coord::new(25, 25)] {
                            for radius in [0, 1, 4, 12, 60] {
                                assert_eq!(
                                    board.within_distance(start, radius),
                                    queue_bfs(&board, start, radius)
                                );
                            }
                        }
                    }
                }
            }

            #[test]
            fn edges_do_not_wrap_between_rows_or_columns() {
                let mut board = BitBoard::<64>::default();
                for p in [
                    Coord::new(0, 0),
                    Coord::new(0, 63),
                    Coord::new(1, 0),
                    Coord::new(63, 63),
                ] {
                    board.insert(p);
                }
                let start = Coord::new(0, 63);
                let reached = board.within_distance(start, 100);
                let mut expected = BitBoard::default();
                expected.insert(start);
                assert_eq!(reached, expected);
                assert_eq!(reached, queue_bfs(&board, start, 100));
            }
        }
    }
    pub mod diagnostics {
        use itertools::Itertools;
        use std::collections::HashMap;
        use std::{
            borrow::Cow,
            cell::RefCell,
            fmt::Display,
            io::{self, IsTerminal as _},
            rc::Rc,
            time::{Duration, Instant},
        };

        /// プログラムの経過時間を計測する。
        pub struct Timer {
            start: Instant,
        }

        impl Default for Timer {
            fn default() -> Self {
                Self {
                    start: Instant::now(),
                }
            }
        }

        impl Timer {
            pub fn elapsed(&self) -> Duration {
                self.start.elapsed()
            }
        }

        /// 実行時間を計測・集計する構造体
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::diagnostics::Perf;
        /// use cp_lib_rs::perf;
        ///
        /// // 計測グループを作成する
        /// // dropされるときに計測結果を出力する
        /// let mut perf = Perf::new("Group");
        /// let mut _sum = 0u64;
        ///
        /// for i in 0..100000 {
        ///     // start-stop間の処理時間を計測する
        ///     let sw = perf.start("sum");
        ///     _sum += i;
        ///     sw.stop();
        ///
        ///     // 名前は&'static strでもStringでもOK
        ///     let sw = perf.start(format!("no-op"));
        ///     sw.stop();
        /// }
        ///
        /// let mut _sum_sqrt = 0f64;
        ///
        /// for i in 0..100000 {
        ///     // 明示的にstop()を呼ばなくても、スコープを抜ける際に自動でstopする
        ///     let _sw = perf.start("sum sqrt");
        ///     _sum_sqrt += (i as f64).sqrt();
        /// }
        ///
        /// let mut _sum_sq = 0u64;
        ///
        /// for i in 0..100000 {
        ///     // perfのインスタンス化が面倒な場合はシングルトンを使う
        ///     let sw = Perf::start_singleton("sum sq");
        ///     _sum_sq += i * i;
        ///     sw.stop();
        /// }
        ///
        /// let mut _sum_pow = 0f64;
        ///
        /// for i in 0..100000 {
        ///     // マクロでショートハンド化もできる
        ///     _sum_pow += perf!("sum pow", (i as f64).powf(3.1415926));
        /// }
        /// ```
        pub struct Perf {
            name: Option<Cow<'static, str>>,
            measures: HashMap<Cow<'static, str>, Measure>,
        }

        impl Perf {
            thread_local!(static SINGLETON: Rc<RefCell<Perf>> = Rc::new(RefCell::new(Perf::new("Singleton"))));

            /// 新しい Perf インスタンスを作成する
            pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
                Self {
                    name: Some(name.into()),
                    measures: HashMap::default(),
                }
            }

            /// 匿名の Perf インスタンスを作成する
            pub fn new_anonymous() -> Self {
                Self {
                    name: None,
                    measures: HashMap::default(),
                }
            }

            /// 計測を開始する
            pub fn start(&mut self, name: impl Into<Cow<'static, str>>) -> StopWatch<&mut Perf> {
                let name = name.into();

                StopWatch {
                    start: Instant::now(),
                    perf: self,
                    name,
                }
            }

            /// 計測を開始する(スレッドごとのシングルトン)
            pub fn start_singleton(
                name: impl Into<Cow<'static, str>>,
            ) -> StopWatch<Rc<RefCell<Perf>>> {
                Self::SINGLETON.with(|perf| StopWatch {
                    start: Instant::now(),
                    perf: perf.clone(),
                    name: name.into(),
                })
            }
        }

        impl Drop for Perf {
            fn drop(&mut self) {
                if self.measures.is_empty() {
                    return;
                }

                // ターミナルかどうかで色を付けるかどうか分岐
                let is_tty = io::stderr().is_terminal();
                let name = self.name.as_deref().unwrap_or("Anonymous");

                if is_tty {
                    // コンソール → 色付き
                    eprintln!("\x1b[35m[{name}] Performance measures\x1b[0m");
                } else {
                    // リダイレクト → 色なし
                    eprintln!("[{name}] Performance measures");
                }

                for (name, measure) in self
                    .measures
                    .iter()
                    .sorted_unstable_by(|(a, _), (b, _)| a.as_ref().cmp(b.as_ref()))
                {
                    eprintln!("{name}: {measure}");
                }
            }
        }

        #[macro_export]
        macro_rules! perf {
            ($name: expr, $body: expr) => {{
                let sw = Perf::start_singleton($name);
                let result = $body;
                sw.stop();
                result
            }};
        }

        pub struct StopWatch<M: WithMut<Perf>> {
            start: Instant,
            perf: M,
            name: Cow<'static, str>,
        }

        impl<M: WithMut<Perf>> StopWatch<M> {
            pub fn stop(self) {
                std::mem::drop(self);
            }
        }

        impl<M: WithMut<Perf>> Drop for StopWatch<M> {
            fn drop(&mut self) {
                let duration = self.start.elapsed();
                let name = std::mem::take(&mut self.name);

                self.perf.with_mut(|perf| {
                    perf.measures
                        .entry(name)
                        .or_default()
                        .add_measure(&duration)
                })
            }
        }

        #[derive(Debug, Clone, Copy, Default)]
        struct Measure {
            sum: f64,
            sum_sq: f64,
            cnt: usize,
        }

        impl Measure {
            fn add_measure(&mut self, duration: &Duration) {
                let sec = duration.as_secs_f64();
                self.sum += sec;
                self.sum_sq += sec * sec;
                self.cnt += 1;
            }

            fn mean(&self) -> Duration {
                assert_ne!(self.cnt, 0);
                Duration::from_secs_f64(self.sum / self.cnt as f64)
            }

            fn std_dev(&self) -> Duration {
                assert_ne!(self.cnt, 0);

                // Durationへの丸めは最後に行い、浮動小数点の丸め誤差も吸収する。
                let mean = self.sum / self.cnt as f64;
                let variance = ((self.sum_sq / self.cnt as f64) - (mean * mean)).max(0.0);
                Duration::from_secs_f64(variance.sqrt())
            }
        }

        impl Display for Measure {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(
                    f,
                    "{:?} ± {:?} ({} samples)",
                    self.mean(),
                    self.std_dev(),
                    self.cnt
                )
            }
        }

        /// `&mut T` と `Rc<RefCell<T>>` を統一的に扱って処理を行うためのトレイト
        pub trait WithMut<T> {
            fn with_mut<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R;
        }

        impl<T> WithMut<T> for &mut T {
            fn with_mut<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
                f(*self)
            }
        }

        impl<T> WithMut<T> for Rc<RefCell<T>> {
            fn with_mut<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
                let mut guard = self.borrow_mut();
                f(&mut *guard)
            }
        }

        #[cfg(test)]
        mod tests {
            use super::*;

            #[test]
            fn standard_deviation_handles_subnanosecond_mean() {
                let mut measure = Measure::default();
                for nanos in [1000, 1001, 1001] {
                    measure.add_measure(&Duration::from_nanos(nanos));
                }
                assert_eq!(measure.mean(), Duration::from_nanos(1001));
                assert_eq!(measure.std_dev(), Duration::ZERO);
                assert!(!measure.to_string().is_empty());
            }

            #[test]
            fn standard_deviation_matches_known_values() {
                for (samples, expected) in
                    [(vec![1000, 2000], 500), (vec![1001; 1000], 0), (vec![0], 0)]
                {
                    let mut measure = Measure::default();
                    for nanos in samples {
                        measure.add_measure(&Duration::from_nanos(nanos));
                    }
                    assert_eq!(measure.std_dev(), Duration::from_nanos(expected));
                }
            }
        }
    }
    pub mod graph {
        use std::ops::Index;

        /// 隣接リスト形式のグラフを行圧縮したグラフ
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::graph::{RowCompressedGraph, UnweightedEdge};
        /// use itertools::Itertools;
        ///
        /// let nodes = vec!["hoge", "fuga", "piyo"];
        /// let edges = vec![
        ///     (1, UnweightedEdge::new(2)),
        ///     (2, UnweightedEdge::new(0)),
        ///     (0, UnweightedEdge::new(1)),
        /// ];
        /// let graph = RowCompressedGraph::new(3, nodes, edges);
        ///
        /// assert_eq!(graph.len(), 3);
        /// assert_eq!(graph.nodes()[0], "hoge");
        /// assert_eq!(graph[0].iter().sorted().copied().collect_vec(), [UnweightedEdge::new(1)]);
        /// ```
        #[derive(Debug, Clone)]
        pub struct RowCompressedGraph<V, E> {
            nodes: Vec<V>,
            edges: Vec<E>,
            pos: Vec<usize>,
            len: usize,
        }

        impl<V, E> RowCompressedGraph<V, E> {
            pub fn new(n: usize, nodes: Vec<V>, edges: Vec<(usize, E)>) -> Self {
                assert!(nodes.len() == n);
                let mut raw_edges = edges;
                raw_edges.sort_unstable_by_key(|(u, _)| *u);
                let mut edges = Vec::with_capacity(raw_edges.len());
                let mut pos = vec![0; n + 1];
                let mut index = 0;

                for (i, (u, e)) in raw_edges.into_iter().enumerate() {
                    assert!(u < n);

                    while index < u {
                        index += 1;
                        pos[index] = i;
                    }

                    edges.push(e);
                }

                pos[index + 1..].fill(edges.len());

                Self {
                    nodes,
                    edges,
                    pos,
                    len: n,
                }
            }

            #[allow(clippy::len_without_is_empty)]
            pub fn len(&self) -> usize {
                self.len
            }

            pub fn nodes(&self) -> &[V] {
                &self.nodes
            }

            pub fn nodes_mut(&mut self) -> &mut [V] {
                &mut self.nodes
            }
        }

        impl<E> RowCompressedGraph<(), E> {
            pub fn new_edges(n: usize, edges: Vec<(usize, E)>) -> Self {
                Self::new(n, vec![(); n], edges)
            }
        }

        impl<V, E> Index<usize> for RowCompressedGraph<V, E> {
            type Output = [E];

            fn index(&self, index: usize) -> &Self::Output {
                let start = self.pos[index];
                let end = self.pos[index + 1];
                &self.edges[start..end]
            }
        }

        pub trait EdgeTo {
            fn to(&self) -> usize;
        }

        pub trait EdgeWeight<T>: EdgeTo {
            fn weight(&self) -> &T;
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct UnweightedEdge {
            to: usize,
        }

        impl UnweightedEdge {
            pub fn new(to: usize) -> Self {
                Self { to }
            }
        }

        impl EdgeTo for UnweightedEdge {
            fn to(&self) -> usize {
                self.to
            }
        }

        #[derive(Debug, Clone, Copy)]
        pub struct WeightedEdge<T> {
            to: usize,
            weight: T,
        }

        impl<T> WeightedEdge<T> {
            pub fn new(to: usize, weight: T) -> Self {
                Self { to, weight }
            }
        }

        impl<T> EdgeTo for WeightedEdge<T> {
            fn to(&self) -> usize {
                self.to
            }
        }

        impl<T> EdgeWeight<T> for WeightedEdge<T> {
            fn weight(&self) -> &T {
                &self.weight
            }
        }
    }
    pub mod grid {
        use std::{
            fmt::Display,
            ops::{
                Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub,
                SubAssign,
            },
        };

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
        pub struct Coord {
            row: u8,
            col: u8,
        }

        impl Coord {
            pub const fn new(row: usize, col: usize) -> Self {
                Self {
                    row: row as u8,
                    col: col as u8,
                }
            }

            pub const fn row(&self) -> usize {
                self.row as usize
            }

            pub const fn col(&self) -> usize {
                self.col as usize
            }

            pub fn in_map(&self, size: usize) -> bool {
                self.row < size as u8 && self.col < size as u8
            }

            pub const fn to_index(&self, size: usize) -> CoordIndex {
                CoordIndex(self.row as usize * size + self.col as usize)
            }

            pub const fn dist(&self, other: &Self) -> usize {
                Self::dist_1d(self.row, other.row) + Self::dist_1d(self.col, other.col)
            }

            const fn dist_1d(x0: u8, x1: u8) -> usize {
                x0.abs_diff(x1) as usize
            }
        }

        impl Display for Coord {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(f, "({}, {})", self.row, self.col)
            }
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
        pub struct CoordIndex(pub usize);

        impl CoordIndex {
            pub const fn to_coord(&self, size: usize) -> Coord {
                Coord::new(self.0 / size, self.0 % size)
            }
        }

        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
        pub struct CoordDiff {
            dr: i8,
            dc: i8,
        }

        impl CoordDiff {
            pub const fn new(dr: i32, dc: i32) -> Self {
                Self {
                    dr: dr as i8,
                    dc: dc as i8,
                }
            }

            pub const fn invert(&self) -> Self {
                Self {
                    dr: -self.dr,
                    dc: -self.dc,
                }
            }

            pub const fn dr(&self) -> i32 {
                self.dr as i32
            }

            pub const fn dc(&self) -> i32 {
                self.dc as i32
            }
        }

        impl Display for CoordDiff {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(f, "({}, {})", self.dr, self.dc)
            }
        }

        impl Add<CoordDiff> for Coord {
            type Output = Coord;

            fn add(self, rhs: CoordDiff) -> Self::Output {
                Coord {
                    row: self.row.wrapping_add(rhs.dr as u8),
                    col: self.col.wrapping_add(rhs.dc as u8),
                }
            }
        }

        impl AddAssign<CoordDiff> for Coord {
            fn add_assign(&mut self, rhs: CoordDiff) {
                self.row = self.row.wrapping_add(rhs.dr as u8);
                self.col = self.col.wrapping_add(rhs.dc as u8);
            }
        }

        impl Add<CoordDiff> for CoordDiff {
            type Output = CoordDiff;

            fn add(self, rhs: CoordDiff) -> Self::Output {
                CoordDiff {
                    dr: self.dr + rhs.dr,
                    dc: self.dc + rhs.dc,
                }
            }
        }

        impl Add<Coord> for CoordDiff {
            type Output = Coord;

            fn add(self, rhs: Coord) -> Self::Output {
                rhs + self
            }
        }

        impl Sub<CoordDiff> for Coord {
            type Output = Coord;

            fn sub(self, rhs: CoordDiff) -> Self::Output {
                Coord {
                    row: self.row.wrapping_sub(rhs.dr as u8),
                    col: self.col.wrapping_sub(rhs.dc as u8),
                }
            }
        }

        impl SubAssign<CoordDiff> for Coord {
            fn sub_assign(&mut self, rhs: CoordDiff) {
                *self = *self - rhs;
            }
        }

        // Differences outside the i8 range wrap, as in CoordDiff::new.
        impl Sub<Coord> for Coord {
            type Output = CoordDiff;

            fn sub(self, rhs: Coord) -> Self::Output {
                CoordDiff::new(
                    self.row as i32 - rhs.row as i32,
                    self.col as i32 - rhs.col as i32,
                )
            }
        }

        impl Sub<CoordDiff> for CoordDiff {
            type Output = CoordDiff;

            fn sub(self, rhs: CoordDiff) -> Self::Output {
                CoordDiff {
                    dr: self.dr - rhs.dr,
                    dc: self.dc - rhs.dc,
                }
            }
        }

        impl SubAssign<CoordDiff> for CoordDiff {
            fn sub_assign(&mut self, rhs: CoordDiff) {
                *self = *self - rhs;
            }
        }

        // Scalar operations use i32 arithmetic, then narrow as in CoordDiff::new.
        impl Mul<i32> for CoordDiff {
            type Output = CoordDiff;

            fn mul(self, rhs: i32) -> Self::Output {
                CoordDiff::new(self.dr() * rhs, self.dc() * rhs)
            }
        }

        impl Mul<CoordDiff> for i32 {
            type Output = CoordDiff;

            fn mul(self, rhs: CoordDiff) -> Self::Output {
                rhs * self
            }
        }

        impl MulAssign<i32> for CoordDiff {
            fn mul_assign(&mut self, rhs: i32) {
                *self = *self * rhs;
            }
        }

        impl Div<i32> for CoordDiff {
            type Output = CoordDiff;

            fn div(self, rhs: i32) -> Self::Output {
                CoordDiff::new(self.dr() / rhs, self.dc() / rhs)
            }
        }

        impl DivAssign<i32> for CoordDiff {
            fn div_assign(&mut self, rhs: i32) {
                *self = *self / rhs;
            }
        }

        impl AddAssign<CoordDiff> for CoordDiff {
            fn add_assign(&mut self, rhs: CoordDiff) {
                self.dr += rhs.dr;
                self.dc += rhs.dc;
            }
        }

        impl Neg for CoordDiff {
            type Output = Self;

            fn neg(self) -> Self::Output {
                Self {
                    dr: -self.dr,
                    dc: -self.dc,
                }
            }
        }

        pub const ADJACENTS: [CoordDiff; 4] = [
            CoordDiff::new(-1, 0),
            CoordDiff::new(0, 1),
            CoordDiff::new(1, 0),
            CoordDiff::new(0, -1),
        ];

        pub const U: usize = 0;
        pub const R: usize = 1;
        pub const D: usize = 2;
        pub const L: usize = 3;
        pub const DIRECTIONS: [char; 4] = ['U', 'R', 'D', 'L'];

        #[derive(Debug, Clone)]
        pub struct Map2d<T> {
            size: usize,
            map: Vec<T>,
        }

        impl<T> Map2d<T> {
            pub fn new(map: Vec<T>, size: usize) -> Self {
                debug_assert!(size * size == map.len());
                Self { size, map }
            }

            pub fn from_fn(mut f: impl FnMut(Coord) -> T, size: usize) -> Self {
                let mut map = Vec::with_capacity(size * size);

                for row in 0..size {
                    for col in 0..size {
                        map.push(f(Coord::new(row, col)));
                    }
                }

                Self { size, map }
            }

            pub fn iter(&self) -> impl Iterator<Item = &T> {
                self.map.iter()
            }
        }

        impl<T: Default + Clone> Map2d<T> {
            pub fn with_default(size: usize) -> Self {
                let map = vec![T::default(); size * size];
                Self { size, map }
            }
        }

        impl<T> Index<Coord> for Map2d<T> {
            type Output = T;

            #[inline]
            fn index(&self, coordinate: Coord) -> &Self::Output {
                &self.map[coordinate.to_index(self.size).0]
            }
        }

        impl<T> IndexMut<Coord> for Map2d<T> {
            #[inline]
            fn index_mut(&mut self, coordinate: Coord) -> &mut Self::Output {
                &mut self.map[coordinate.to_index(self.size).0]
            }
        }

        impl<T> Index<&Coord> for Map2d<T> {
            type Output = T;

            #[inline]
            fn index(&self, coordinate: &Coord) -> &Self::Output {
                &self.map[coordinate.to_index(self.size).0]
            }
        }

        impl<T> IndexMut<&Coord> for Map2d<T> {
            #[inline]
            fn index_mut(&mut self, coordinate: &Coord) -> &mut Self::Output {
                &mut self.map[coordinate.to_index(self.size).0]
            }
        }

        impl<T> Index<usize> for Map2d<T> {
            type Output = [T];

            #[inline]
            fn index(&self, row: usize) -> &Self::Output {
                let begin = row * self.size;
                let end = begin + self.size;
                &self.map[begin..end]
            }
        }

        impl<T> IndexMut<usize> for Map2d<T> {
            #[inline]
            fn index_mut(&mut self, row: usize) -> &mut Self::Output {
                let begin = row * self.size;
                let end = begin + self.size;
                &mut self.map[begin..end]
            }
        }

        impl<T> Index<CoordIndex> for Map2d<T> {
            type Output = T;

            #[inline]
            fn index(&self, index: CoordIndex) -> &Self::Output {
                &self.map[index.0]
            }
        }

        impl<T> IndexMut<CoordIndex> for Map2d<T> {
            #[inline]
            fn index_mut(&mut self, index: CoordIndex) -> &mut Self::Output {
                &mut self.map[index.0]
            }
        }

        #[derive(Debug, Clone)]
        pub struct ConstMap2d<T, const N: usize, const LEN: usize> {
            map: [T; LEN],
        }

        impl<T, const N: usize, const LEN: usize> ConstMap2d<T, N, LEN> {
            pub fn new(map: Vec<T>) -> Self {
                assert_eq!(LEN, N * N);
                assert_eq!(map.len(), LEN);
                let Ok(map) = map.try_into() else {
                    unreachable!("長さ検証済みのVecから配列への変換に失敗しました。");
                };

                Self { map }
            }

            pub fn from_fn(mut f: impl FnMut(Coord) -> T) -> Self {
                assert_eq!(LEN, N * N);
                let map = std::array::from_fn(|index| f(Coord::new(index / N, index % N)));

                Self { map }
            }

            pub fn iter(&self) -> impl Iterator<Item = &T> {
                self.map.iter()
            }
        }

        impl<T: Default, const N: usize, const LEN: usize> ConstMap2d<T, N, LEN> {
            pub fn with_default() -> Self {
                assert_eq!(LEN, N * N);
                let map = std::array::from_fn(|_| T::default());

                Self { map }
            }
        }

        impl<T, const N: usize, const LEN: usize> Index<Coord> for ConstMap2d<T, N, LEN> {
            type Output = T;

            #[inline]
            fn index(&self, coordinate: Coord) -> &Self::Output {
                &self.map[coordinate.to_index(N).0]
            }
        }

        impl<T, const N: usize, const LEN: usize> IndexMut<Coord> for ConstMap2d<T, N, LEN> {
            #[inline]
            fn index_mut(&mut self, coordinate: Coord) -> &mut Self::Output {
                &mut self.map[coordinate.to_index(N).0]
            }
        }

        impl<T, const N: usize, const LEN: usize> Index<&Coord> for ConstMap2d<T, N, LEN> {
            type Output = T;

            #[inline]
            fn index(&self, coordinate: &Coord) -> &Self::Output {
                &self.map[coordinate.to_index(N).0]
            }
        }

        impl<T, const N: usize, const LEN: usize> IndexMut<&Coord> for ConstMap2d<T, N, LEN> {
            #[inline]
            fn index_mut(&mut self, coordinate: &Coord) -> &mut Self::Output {
                &mut self.map[coordinate.to_index(N).0]
            }
        }

        impl<T, const N: usize, const LEN: usize> Index<usize> for ConstMap2d<T, N, LEN> {
            type Output = [T];

            #[inline]
            fn index(&self, row: usize) -> &Self::Output {
                let begin = row * N;
                let end = begin + N;
                &self.map[begin..end]
            }
        }

        impl<T, const N: usize, const LEN: usize> IndexMut<usize> for ConstMap2d<T, N, LEN> {
            #[inline]
            fn index_mut(&mut self, row: usize) -> &mut Self::Output {
                let begin = row * N;
                let end = begin + N;
                &mut self.map[begin..end]
            }
        }

        impl<T, const N: usize, const LEN: usize> Index<CoordIndex> for ConstMap2d<T, N, LEN> {
            type Output = T;

            #[inline]
            fn index(&self, index: CoordIndex) -> &Self::Output {
                &self.map[index.0]
            }
        }

        impl<T, const N: usize, const LEN: usize> IndexMut<CoordIndex> for ConstMap2d<T, N, LEN> {
            #[inline]
            fn index_mut(&mut self, index: CoordIndex) -> &mut Self::Output {
                &mut self.map[index.0]
            }
        }

        #[cfg(test)]
        mod test {
            use super::{ConstMap2d, Coord, CoordDiff, Map2d};

            #[test]
            fn coord_add() {
                let c = Coord::new(2, 4);
                let d = CoordDiff::new(-3, 5);
                let actual = c + d;

                let expected = Coord::new(!0, 9);
                assert_eq!(expected, actual);
            }

            #[test]
            fn coord_add_assign() {
                let mut c = Coord::new(2, 4);
                let d = CoordDiff::new(-3, 5);
                c += d;

                let expected = Coord::new(!0, 9);
                assert_eq!(expected, c);
            }

            #[test]
            fn coord_translation_round_trip() {
                for row in 0..=255 {
                    let c = Coord::new(row, 255 - row);
                    for dr in -128..=127 {
                        let d = CoordDiff::new(dr, -1 - dr);
                        assert_eq!(c + d, d + c);
                        assert_eq!((c + d) - d, c);
                        assert_eq!((c + d) - c, d);

                        let mut translated = c;
                        translated -= d;
                        assert_eq!(translated + d, c);
                    }
                }
            }

            #[test]
            fn coord_difference() {
                assert_eq!(Coord::new(2, 9) - Coord::new(5, 4), CoordDiff::new(-3, 5));
                assert_eq!(
                    Coord::new(255, 0) - Coord::new(0, 255),
                    CoordDiff::new(-1, 1)
                );
            }

            #[test]
            fn coord_diff_arithmetic() {
                let a = CoordDiff::new(-3, 5);
                let b = CoordDiff::new(7, -2);
                assert_eq!(a + b, CoordDiff::new(4, 3));
                assert_eq!(a - b, CoordDiff::new(-10, 7));
                assert_eq!(-a, a.invert());
                assert_eq!(a + (-a), CoordDiff::default());

                let mut d = a;
                d += b;
                assert_eq!(d, a + b);
                d -= b;
                assert_eq!(d, a);
            }

            #[test]
            fn coord_diff_scalar_arithmetic() {
                let d = CoordDiff::new(-3, 5);
                assert_eq!(d * -2, CoordDiff::new(6, -10));
                assert_eq!(-2 * d, d * -2);
                assert_eq!(d * 0, CoordDiff::default());
                assert_eq!(d / 2, CoordDiff::new(-1, 2));
                assert_eq!(d / -2, CoordDiff::new(1, -2));
                assert_eq!(CoordDiff::new(64, -128) * 2, CoordDiff::new(-128, 0));
                assert_eq!(CoordDiff::new(-128, 0) / -1, CoordDiff::new(-128, 0));
                assert_eq!(d / 256, CoordDiff::default());

                let mut scaled = d;
                scaled *= -2;
                assert_eq!(scaled, CoordDiff::new(6, -10));
                scaled /= -2;
                assert_eq!(scaled, d);
            }

            #[test]
            #[should_panic]
            fn coord_diff_divide_by_zero() {
                let _ = CoordDiff::new(1, 2) / 0;
            }

            #[test]
            fn map_new() {
                let map = Map2d::new(vec![0, 1, 2, 3], 2);
                let actual = map[Coord::new(1, 0)];
                let expected = 2;
                assert_eq!(expected, actual);
            }

            #[test]
            fn map_default() {
                let map = Map2d::with_default(2);
                let actual = map[Coord::new(1, 0)];
                let expected = 0;
                assert_eq!(expected, actual);
            }

            #[test]
            fn const_map_new() {
                let map = ConstMap2d::<_, 2, 4>::new(vec![0, 1, 2, 3]);
                let actual = map[Coord::new(1, 0)];
                let expected = 2;
                assert_eq!(expected, actual);
            }

            #[test]
            fn const_map_default() {
                let map = ConstMap2d::<_, 2, 4>::with_default();
                let actual = map[Coord::new(1, 0)];
                let expected = 0;
                assert_eq!(expected, actual);
            }
        }
    }
    pub mod random {
        use num::{FromPrimitive, PrimInt};
        use std::ops::{Range, RangeInclusive};

        /// 外部クレートに依存しないSplitMix64乱数生成器。
        #[derive(Debug, Clone)]
        pub struct Random {
            state: u64,
        }

        impl Random {
            pub fn new(seed: u64) -> Self {
                Self { state: seed }
            }

            pub fn next_u64(&mut self) -> u64 {
                self.state = self.state.wrapping_add(0x9e3779b97f4a7c15);
                let mut z = self.state;
                z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
                z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
                z ^ (z >> 31)
            }

            /// 棄却法により剰余の偏りを除き、0..upperから一様に選ぶ。
            pub fn index(&mut self, upper: usize) -> usize {
                assert!(upper > 0);
                let bound = upper as u64;
                let threshold = bound.wrapping_neg() % bound;
                loop {
                    let value = self.next_u64();
                    if value >= threshold {
                        return (value % bound) as usize;
                    }
                }
            }
        }

        /// 高速な乱数生成の拡張トレイト
        pub trait RandExtension {
            fn fast_gen_range_u64x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T;

            fn fast_gen_range_u32x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T;

            fn fast_gen_range_u32x2<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
            ) -> (T0, T1);

            fn fast_gen_range_u16x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T;

            fn fast_gen_range_u16x2<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
            ) -> (T0, T1);

            fn fast_gen_range_u16x3<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                T2: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
                R2: BoundedRange<T2>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
                range2: R2,
            ) -> (T0, T1, T2);

            fn fast_gen_range_u16x4<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                T2: PrimInt + FromPrimitive,
                T3: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
                R2: BoundedRange<T2>,
                R3: BoundedRange<T3>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
                range2: R2,
                range3: R3,
            ) -> (T0, T1, T2, T3);
        }

        impl RandExtension for Random {
            fn fast_gen_range_u64x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T {
                let rand_value = self.next_u64();
                gen_range_u64(range, rand_value)
            }

            fn fast_gen_range_u32x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T {
                let rand_value = self.next_u64();
                gen_range_u32(range, rand_value as u32)
            }

            fn fast_gen_range_u32x2<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
            ) -> (T0, T1) {
                let rand_value = self.next_u64();
                let v0 = gen_range_u32(range0, rand_value as u32);
                let v1 = gen_range_u32(range1, (rand_value >> 32) as u32);
                (v0, v1)
            }

            fn fast_gen_range_u16x1<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
                &mut self,
                range: R,
            ) -> T {
                let rand_value = self.next_u64();
                gen_range_u16(range, rand_value as u16)
            }

            fn fast_gen_range_u16x2<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
            ) -> (T0, T1) {
                let rand_value = self.next_u64();
                let v0 = gen_range_u16(range0, rand_value as u16);
                let v1 = gen_range_u16(range1, (rand_value >> 16) as u16);
                (v0, v1)
            }

            fn fast_gen_range_u16x3<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                T2: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
                R2: BoundedRange<T2>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
                range2: R2,
            ) -> (T0, T1, T2) {
                let rand_value = self.next_u64();
                let v0 = gen_range_u16(range0, rand_value as u16);
                let v1 = gen_range_u16(range1, (rand_value >> 16) as u16);
                let v2 = gen_range_u16(range2, (rand_value >> 32) as u16);
                (v0, v1, v2)
            }

            fn fast_gen_range_u16x4<
                T0: PrimInt + FromPrimitive,
                T1: PrimInt + FromPrimitive,
                T2: PrimInt + FromPrimitive,
                T3: PrimInt + FromPrimitive,
                R0: BoundedRange<T0>,
                R1: BoundedRange<T1>,
                R2: BoundedRange<T2>,
                R3: BoundedRange<T3>,
            >(
                &mut self,
                range0: R0,
                range1: R1,
                range2: R2,
                range3: R3,
            ) -> (T0, T1, T2, T3) {
                let rand_value = self.next_u64();
                let v0 = gen_range_u16(range0, rand_value as u16);
                let v1 = gen_range_u16(range1, (rand_value >> 16) as u16);
                let v2 = gen_range_u16(range2, (rand_value >> 32) as u16);
                let v3 = gen_range_u16(range3, (rand_value >> 48) as u16);
                (v0, v1, v2, v3)
            }
        }

        fn gen_range_u64<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
            range: R,
            rand_value: u64,
        ) -> T {
            assert!(!range.is_empty(), "cannot sample empty range");
            let width = range.width().to_u64().expect("width must fit in u64");
            let start = range.start();
            let value = (((width as u128) * (rand_value as u128)) >> 64) as u64;
            T::from_u64(value).expect("value must fit in T") + start
        }

        fn gen_range_u32<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
            range: R,
            rand_value: u32,
        ) -> T {
            assert!(!range.is_empty(), "cannot sample empty range");
            let width = range.width().to_u32().expect("width must fit in u32");
            let start = range.start();
            let value = (((width as u64) * (rand_value as u64)) >> 32) as u32;
            T::from_u32(value).expect("value must fit in T") + start
        }

        fn gen_range_u16<T: PrimInt + FromPrimitive, R: BoundedRange<T>>(
            range: R,
            rand_value: u16,
        ) -> T {
            assert!(!range.is_empty(), "cannot sample empty range");
            let width = range.width().to_u16().expect("width must fit in u16");
            let start = range.start();
            let value = (((width as u32) * (rand_value as u32)) >> 16) as u16;
            T::from_u16(value).expect("value must fit in T") + start
        }

        pub trait BoundedRange<T> {
            fn start(&self) -> T;
            fn width(&self) -> T;
            fn is_empty(&self) -> bool;
        }

        impl<T: PrimInt> BoundedRange<T> for Range<T> {
            fn start(&self) -> T {
                self.start
            }

            fn width(&self) -> T {
                self.end - self.start
            }

            fn is_empty(&self) -> bool {
                self.start >= self.end
            }
        }

        impl<T: PrimInt> BoundedRange<T> for RangeInclusive<T> {
            fn start(&self) -> T {
                *self.start()
            }

            fn width(&self) -> T {
                *self.end() - *self.start() + T::one()
            }

            fn is_empty(&self) -> bool {
                self.start() > self.end()
            }
        }

        #[cfg(test)]
        mod tests {
            use super::*;
            use std::collections::HashSet;

            #[test]
            fn splitmix64_known_sequence() {
                let mut rng = Random::new(0);
                assert_eq!(rng.next_u64(), 0xe220a8397b1dcdaf);
                assert_eq!(rng.next_u64(), 0x6e789e6aa1b965f4);
            }

            #[test]
            fn index_stays_in_range() {
                let mut rng = Random::new(42);
                for upper in [1, 2, 10, 2500] {
                    for _ in 0..10000 {
                        assert!(rng.index(upper) < upper);
                    }
                }
            }

            fn check_range<R: BoundedRange<usize> + Clone, F: Fn(&mut Random, R) -> usize>(
                range: R,
                generator: F,
            ) {
                let mut rng = Random::new(42);
                let mut values = HashSet::new();
                let start = range.start();
                let width = range.width();
                let end = start + width;

                for _ in 0..10000 {
                    let v = generator(&mut rng, range.clone());
                    assert!(start <= v && v < end, "value {v:?} out of range");
                    values.insert(v);
                }

                for v in start..end {
                    assert!(values.contains(&v), "value {v:?} not generated");
                }
            }

            #[test]
            fn test_fast_gen_range_u64x1() {
                check_range(0usize..10usize, |rng, r| rng.fast_gen_range_u64x1(r));
            }

            #[test]
            #[should_panic(expected = "cannot sample empty range")]
            fn test_fast_gen_range_u64x1_empty_range() {
                let mut rng = Random::new(42);
                let _ = rng.fast_gen_range_u64x1(5usize..5usize);
            }

            #[test]
            fn test_fast_gen_range_u32x1() {
                check_range(0usize..10usize, |rng, r| rng.fast_gen_range_u32x1(r));
            }

            #[test]
            fn test_fast_gen_range_u32x2() {
                let mut rng = Random::new(123);
                let mut set0 = HashSet::new();
                let mut set1 = HashSet::new();

                for _ in 0..10000 {
                    let (v0, v1) = rng.fast_gen_range_u32x2(0u32..5u32, 10u32..=15u32);
                    assert!((0..5).contains(&v0));
                    assert!((10..=15).contains(&v1));
                    set0.insert(v0);
                    set1.insert(v1);
                }

                for v in 0u32..5u32 {
                    assert!(set0.contains(&v));
                }

                for v in 10u32..=15u32 {
                    assert!(set1.contains(&v));
                }
            }

            #[test]
            fn test_fast_gen_range_u16x1() {
                check_range(0usize..10usize, |rng, r| rng.fast_gen_range_u16x1(r));
            }

            #[test]
            fn test_fast_gen_range_u16x2() {
                let mut rng = Random::new(456);
                let mut set0 = HashSet::new();
                let mut set1 = HashSet::new();

                for _ in 0..10000 {
                    let (v0, v1) = rng.fast_gen_range_u16x2(0u16..5u16, 10u16..15u16);
                    assert!((0..5).contains(&v0));
                    assert!((10..15).contains(&v1));
                    set0.insert(v0);
                    set1.insert(v1);
                }

                for v in 0u16..5u16 {
                    assert!(set0.contains(&v));
                }

                for v in 10u16..15u16 {
                    assert!(set1.contains(&v));
                }
            }

            #[test]
            fn test_fast_gen_range_u16x3() {
                let mut rng = Random::new(789);
                let mut set0 = HashSet::new();
                let mut set1 = HashSet::new();
                let mut set2 = HashSet::new();

                for _ in 0..10000 {
                    let (v0, v1, v2) =
                        rng.fast_gen_range_u16x3(0u16..3u16, 10u16..13u16, 20u16..=23u16);
                    assert!((0..3).contains(&v0));
                    assert!((10..13).contains(&v1));
                    assert!((20..=23).contains(&v2));
                    set0.insert(v0);
                    set1.insert(v1);
                    set2.insert(v2);
                }

                for v in 0u16..3u16 {
                    assert!(set0.contains(&v));
                }

                for v in 10u16..13u16 {
                    assert!(set1.contains(&v));
                }

                for v in 20u16..=23u16 {
                    assert!(set2.contains(&v));
                }
            }

            #[test]
            fn test_fast_gen_range_u16x4() {
                let mut rng = Random::new(321);
                let mut set0 = HashSet::new();
                let mut set1 = HashSet::new();
                let mut set2 = HashSet::new();
                let mut set3 = HashSet::new();

                for _ in 0..10000 {
                    let (v0, v1, v2, v3) = rng.fast_gen_range_u16x4(
                        0u16..2u16,
                        10u16..12u16,
                        20u16..=22u16,
                        30u16..32u16,
                    );
                    assert!((0..2).contains(&v0));
                    assert!((10..12).contains(&v1));
                    assert!((20..=22).contains(&v2));
                    assert!((30..32).contains(&v3));
                    set0.insert(v0);
                    set1.insert(v1);
                    set2.insert(v2);
                    set3.insert(v3);
                }

                for v in 0u16..2u16 {
                    assert!(set0.contains(&v));
                }

                for v in 10u16..12u16 {
                    assert!(set1.contains(&v));
                }

                for v in 20u16..=22u16 {
                    assert!(set2.contains(&v));
                }

                for v in 30u16..32u16 {
                    assert!(set3.contains(&v));
                }
            }
        }
    }
    pub mod util {
        //! よく使われるユーティリティ関数をまとめたモジュール

        use std::{
            fmt::Display,
            io::{self, BufWriter, Write as _},
        };

        use num::PrimInt;

        /// 最小値と最大値を更新するトレイト
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::util::ChangeMinMax;
        ///
        /// let mut x = 10;
        /// assert!(x.change_min(3));
        /// assert_eq!(x, 3);
        /// ```
        pub trait ChangeMinMax {
            fn change_min(&mut self, v: Self) -> bool;
            fn change_max(&mut self, v: Self) -> bool;
        }

        impl<T: PartialOrd> ChangeMinMax for T {
            fn change_min(&mut self, v: T) -> bool {
                *self > v && {
                    *self = v;
                    true
                }
            }

            fn change_max(&mut self, v: T) -> bool {
                *self < v && {
                    *self = v;
                    true
                }
            }
        }

        /// 条件に従ってYes/Noを出力する
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::yesno;
        ///
        /// let n = 3;
        /// yesno!(3 % 2 == 0)
        /// ```
        #[macro_export]
        macro_rules! yesno {
            ($p:expr) => {
                if $p {
                    println!("Yes");
                } else {
                    println!("No");
                }
            };
        }

        /// 標準出力・標準エラー出力に出力するトレイト
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::util::PrintLine as _;
        ///
        /// let x = 5;
        /// x.println();
        /// x.eprintln();
        ///
        /// let y = [1, 2, 3];
        /// y.println();
        /// y.eprintln();
        /// ```
        pub trait PrintLine {
            fn println(&self);
            fn eprintln(&self);
        }

        /// 単体値版
        impl<T: Display> PrintLine for T {
            fn println(&self) {
                println!("{self}");
            }

            fn eprintln(&self) {
                eprintln!("{self}");
            }
        }

        /// スライス版
        impl<T: Display> PrintLine for [T] {
            fn println(&self) {
                let stdout = io::stdout();
                let mut out = BufWriter::new(stdout.lock());

                let mut first = true;
                for x in self {
                    if !first {
                        out.write_all(b" ").unwrap();
                    }
                    write!(out, "{x}").unwrap();
                    first = false;
                }

                out.write_all(b"\n").unwrap();
                // drop(out)でflush
            }

            fn eprintln(&self) {
                let stderr = io::stderr();
                let mut out = BufWriter::new(stderr.lock());

                let mut first = true;
                for x in self {
                    if !first {
                        out.write_all(b" ").unwrap();
                    }
                    write!(out, "{x}").unwrap();
                    first = false;
                }

                out.write_all(b"\n").unwrap();
            }
        }

        /// 多次元配列を作成する
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::mat;
        ///
        /// let a = mat![0; 4; 3];
        /// assert_eq!(a, vec![vec![0; 3]; 4]);
        /// ```
        #[macro_export]
        macro_rules! mat {
	($($e:expr),*) => { vec![$($e),*] };
	($($e:expr,)*) => { vec![$($e),*] };
	($e:expr; $d:expr) => { vec![$e; $d] };
	($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] };
}

        /// 整数の二分探索を行う
        ///
        /// # Examples
        ///
        /// ```
        /// use cp_lib_rs::util::binary_search;
        ///
        /// let result = binary_search(0, 10, |x| x * x <= 5);
        /// assert_eq!(result, 2);
        /// ```
        pub fn binary_search<T: PrimInt>(ok: T, ng: T, f: impl Fn(T) -> bool) -> T {
            let mut ok = ok;
            let mut ng = ng;

            while ok.max(ng) - ok.min(ng) > T::one() {
                let mid = (ok + ng) / (T::one() << 1);

                if f(mid) {
                    ok = mid;
                } else {
                    ng = mid;
                }
            }

            ok
        }

        #[cfg(test)]
        mod test {
            use super::*;

            #[test]
            fn binary_search_test() {
                assert_eq!(binary_search(0, 10, |x| x * x <= 5), 2);
                assert_eq!(binary_search(10, 0, |x| x * x >= 5), 3);
            }
        }
    }
}
pub mod problem {
    use std::fmt::{self, Display, Formatter};
    use std::io::{self, BufRead};

    use proconio::{input, marker::Bytes, source::once::OnceSource};

    use crate::library::grid::{Coord, Map2d};

    #[derive(Debug, Clone)]
    pub struct Input {
        /// 各マスの乾燥度。0は木のないマス、1〜9は木の乾燥度を表す。
        pub d: Map2d<u8>,
    }

    impl Input {
        /// 森の一辺のマス数。
        pub const N: usize = 50;
        /// 伐採できる木の本数の上限。
        pub const K: usize = 100;

        pub fn read() -> Self {
            Self::read_from(io::stdin().lock())
        }

        fn read_from(reader: impl BufRead) -> Self {
            let mut source = OnceSource::new(reader);
            input! {
                from &mut source,
                n: usize,
                k: usize,
            }
            assert_eq!(n, Self::N, "入力のNが定数と一致しません");
            assert_eq!(k, Self::K, "入力のKが定数と一致しません");
            let mut cells = Vec::with_capacity(Self::N * Self::N);
            for _ in 0..Self::N {
                input! { from &mut source, row: Bytes }
                assert_eq!(row.len(), Self::N, "乾燥度の行の長さがNと一致しません");
                for digit in row {
                    assert!(digit.is_ascii_digit(), "乾燥度は0〜9の数字で指定します");
                    cells.push(digit - b'0');
                }
            }
            Self {
                d: Map2d::new(cells, Self::N),
            }
        }
    }

    #[derive(Debug, Clone, Default)]
    pub struct Output {
        /// 伐採する木のマス(0始まりの行・列)。相異なる木のあるマスをK個以下指定する。
        pub cuts: Vec<Coord>,
    }

    impl Display for Output {
        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
            // 本数は座標列から求め、出力行数との不一致を防ぐ。
            writeln!(f, "{}", self.cuts.len())?;
            for coord in &self.cuts {
                writeln!(f, "{} {}", coord.row(), coord.col())?;
            }
            Ok(())
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn reads_digits_in_row_major_order_including_leading_zero() {
            let mut text = String::from("50 100\n");
            for row in 0..50 {
                for col in 0..50 {
                    text.push(char::from(b'0' + ((row + col) % 10) as u8));
                }
                text.push('\n');
            }
            let input = Input::read_from(text.as_bytes());
            assert_eq!(input.d.iter().count(), 2500);
            for row in 0..50 {
                for col in 0..50 {
                    assert_eq!(input.d[Coord::new(row, col)], ((row + col) % 10) as u8);
                }
            }
        }

        #[test]
        fn formats_sample_output() {
            let output = Output {
                cuts: vec![Coord::new(0, 32), Coord::new(1, 33), Coord::new(2, 34)],
            };
            assert_eq!(output.to_string(), "3\n0 32\n1 33\n2 34\n");
        }

        #[test]
        fn formats_empty_output() {
            assert_eq!(Output::default().to_string(), "0\n");
        }
    }
}
pub mod solver {
    mod vertex_cut {
        mod evaluation {
            use crate::library::{
                grid::{ADJACENTS, Coord, Map2d},
                random::Random,
            };
            use crate::problem::Input;

            const SAMPLES: usize = 20;

            pub(super) struct Evaluator {
                samples: Vec<Map2d<bool>>,
                baseline: u64,
            }

            fn sample_seed(input: &Input) -> u64 {
                // 配布ツールと同じ入力由来のseedで、先頭100サンプルを固定する。
                let mut hash = 1469598103934665603_u64;
                for &d in input.d.iter() {
                    hash ^= u64::from(b'0' + d);
                    hash = hash.wrapping_mul(1099511628211);
                }
                hash ^ (Input::N as u64)
                    .wrapping_mul(1000003)
                    .wrapping_add((Input::K as u64).wrapping_mul(998244353))
            }

            fn component_square_sum(dry: &Map2d<bool>, cut: &Map2d<bool>) -> u64 {
                let mut seen = Map2d::with_default(Input::N);
                let mut queue = Vec::with_capacity(Input::N * Input::N);
                let mut sum = 0;
                for row in 0..Input::N {
                    for col in 0..Input::N {
                        let start = Coord::new(row, col);
                        if seen[start] || !dry[start] || cut[start] {
                            continue;
                        }
                        seen[start] = true;
                        queue.clear();
                        queue.push(start);
                        let mut head = 0;
                        while head < queue.len() {
                            let p = queue[head];
                            head += 1;
                            for diff in ADJACENTS {
                                let next = p + diff;
                                if next.in_map(Input::N) && !seen[next] && dry[next] && !cut[next] {
                                    seen[next] = true;
                                    queue.push(next);
                                }
                            }
                        }
                        sum += (queue.len() as u64).pow(2);
                    }
                }
                sum
            }

            impl Evaluator {
                pub(super) fn new(input: &Input) -> Self {
                    let mut rng = Random::new(sample_seed(input));
                    let thresholds: Vec<u64> = input
                        .d
                        .iter()
                        .map(|&d| u64::from(d) * (1_u64 << 32) / 10)
                        .collect();
                    let samples: Vec<_> = (0..SAMPLES)
                        .map(|_| {
                            let mut cells = Vec::with_capacity(Input::N * Input::N);
                            for pair in thresholds.chunks(2) {
                                let bits = rng.next_u64();
                                cells.push((bits & 0xffff_ffff) < pair[0]);
                                if pair.len() == 2 {
                                    cells.push((bits >> 32) < pair[1]);
                                }
                            }
                            Map2d::new(cells, Input::N)
                        })
                        .collect();
                    let no_cuts = Map2d::with_default(Input::N);
                    let baseline = samples
                        .iter()
                        .map(|sample| component_square_sum(sample, &no_cuts))
                        .sum();
                    Self { samples, baseline }
                }

                pub(super) fn score(&self, cut: &Map2d<bool>) -> i64 {
                    let total: u64 = self
                        .samples
                        .iter()
                        .map(|sample| component_square_sum(sample, cut))
                        .sum();
                    let denominator = (SAMPLES * Input::N * Input::N) as f64;
                    let e0 = self.baseline as f64 / denominator;
                    let e = total as f64 / denominator;
                    // ゼロ近傍の処理・丸めを配布ツールと揃える。
                    (1e6 * (1.0 + (e0 / e.max(1e-12)).log2())).round() as i64
                }
            }

            #[cfg(test)]
            mod tests {
                use super::*;

                #[test]
                fn square_sum_and_cut_splitting() {
                    let mut dry = Map2d::with_default(Input::N);
                    for col in 0..3 {
                        dry[Coord::new(0, col)] = true;
                    }
                    dry[Coord::new(2, 2)] = true;
                    let mut cut = Map2d::with_default(Input::N);
                    assert_eq!(component_square_sum(&dry, &cut), 10);
                    cut[Coord::new(0, 1)] = true;
                    assert_eq!(component_square_sum(&dry, &cut), 3);
                }

                #[test]
                fn no_cut_score_is_one_million_and_samples_are_fixed() {
                    let input = Input {
                        d: Map2d::from_fn(|p| ((p.row() + p.col()) % 10) as u8, Input::N),
                    };
                    let first = Evaluator::new(&input);
                    let second = Evaluator::new(&input);
                    assert_eq!(first.score(&Map2d::with_default(Input::N)), 1_000_000);
                    for (a, b) in first.samples.iter().zip(&second.samples) {
                        assert!(a.iter().eq(b.iter()));
                        for row in 0..Input::N {
                            for col in 0..Input::N {
                                let p = Coord::new(row, col);
                                if input.d[p] == 0 {
                                    assert!(!a[p]);
                                }
                            }
                        }
                    }
                }
            }
        }

        use std::time::Duration;

        use ac_library::MfGraph;

        use crate::library::{
            bitboard::BitBoard,
            diagnostics::Timer,
            grid::{ADJACENTS, Coord, Map2d},
            random::Random,
        };
        use crate::problem::{Input, Output};

        use evaluation::Evaluator;

        const D_THRESHOLD: u8 = 5;
        const PAIR_TRIALS: usize = 1;
        const MIN_DISTANCE: usize = 23;
        const TERMINAL_RADIUS: usize = 12;
        const REMOVE_LOWER: usize = 1;
        const REMOVE_UPPER: usize = 5;
        const TIME_LIMIT: Duration = Duration::from_millis(1950);

        fn components(input: &Input, cut: &Map2d<bool>) -> Vec<Vec<Coord>> {
            let mut seen = Map2d::with_default(Input::N);
            let mut result = Vec::new();
            for row in 0..Input::N {
                for col in 0..Input::N {
                    let start = Coord::new(row, col);
                    if seen[start] || cut[start] || input.d[start] < D_THRESHOLD {
                        continue;
                    }
                    seen[start] = true;
                    let mut vertices = vec![start];
                    let mut head = 0;
                    while head < vertices.len() {
                        let p = vertices[head];
                        head += 1;
                        for diff in ADJACENTS {
                            let next = p + diff;
                            if next.in_map(Input::N)
                                && !seen[next]
                                && !cut[next]
                                && input.d[next] >= D_THRESHOLD
                            {
                                seen[next] = true;
                                vertices.push(next);
                            }
                        }
                    }
                    result.push(vertices);
                }
            }
            result
        }

        fn choose_component<'a>(
            components: &'a [Vec<Coord>],
            rng: &mut Random,
        ) -> Option<&'a [Coord]> {
            let total: usize = components.iter().map(Vec::len).sum();
            if total == 0 {
                return None;
            }
            // 全頂点から1個を選ぶことで、成分サイズに比例した確率になる。
            let mut index = rng.index(total);
            for component in components {
                if index < component.len() {
                    return Some(component);
                }
                index -= component.len();
            }
            unreachable!()
        }

        fn choose_pair(vertices: &[Coord], rng: &mut Random) -> (Coord, Coord) {
            let mut best = (vertices[0], vertices[0]);
            for _ in 0..PAIR_TRIALS {
                let pair = (
                    vertices[rng.index(vertices.len())],
                    vertices[rng.index(vertices.len())],
                );
                if pair.0.dist(&pair.1) > best.0.dist(&best.1) {
                    best = pair;
                }
            }
            best
        }

        fn minimum_vertex_cut(
            input: &Input,
            vertices: &[Coord],
            p1: Coord,
            p2: Coord,
        ) -> Vec<Coord> {
            let len = vertices.len();
            let mut indices = Map2d::from_fn(|_| usize::MAX, Input::N);
            let mut board = BitBoard::<{ Input::N }>::default();
            for (i, &p) in vertices.iter().enumerate() {
                indices[p] = i;
                board.insert(p);
            }
            let source_vertices = board.within_distance(p1, TERMINAL_RADIUS);
            let sink_vertices = board.within_distance(p2, TERMINAL_RADIUS);
            let source = 2 * len;
            let sink = source + 1;
            let mut graph = MfGraph::<i64>::new(sink + 1);
            // 全頂点の有限コストの総和より大きく、隣接辺はカットされない。
            let infinity = (len as i64) * 10009 + 1;
            for (i, &p) in vertices.iter().enumerate() {
                let vin = 2 * i;
                let vout = vin + 1;
                graph.add_edge(vin, vout, 10009 - i64::from(input.d[p]));
                // source/sink内の頂点も有限コストのvin→voutを通るので伐採可能。
                if source_vertices.contains(p) {
                    graph.add_edge(source, vin, infinity);
                }
                if sink_vertices.contains(p) {
                    graph.add_edge(vout, sink, infinity);
                }
                for diff in ADJACENTS {
                    let next = p + diff;
                    if next.in_map(Input::N) && indices[next] != usize::MAX {
                        graph.add_edge(vout, 2 * indices[next], infinity);
                    }
                }
            }
            graph.flow(source, sink);
            let reachable = graph.min_cut(source);
            vertices
                .iter()
                .enumerate()
                .filter_map(|(i, &p)| (reachable[2 * i] && !reachable[2 * i + 1]).then_some(p))
                .collect()
        }

        #[derive(Clone)]
        struct State {
            cut: Map2d<bool>,
            batches: Vec<Vec<Coord>>,
            count: usize,
        }

        impl State {
            fn new() -> Self {
                Self {
                    cut: Map2d::with_default(Input::N),
                    batches: Vec::new(),
                    count: 0,
                }
            }

            fn add(&mut self, batch: Vec<Coord>) {
                for &p in &batch {
                    debug_assert!(!self.cut[p]);
                    self.cut[p] = true;
                }
                self.count += batch.len();
                self.batches.push(batch);
            }

            fn remove_random_batches(&mut self, rng: &mut Random) {
                let number = REMOVE_LOWER + rng.index(REMOVE_UPPER - REMOVE_LOWER + 1);
                // 残っている履歴から毎回一様に選び、重複なしでカットを取り消す。
                for _ in 0..number.min(self.batches.len()) {
                    let index = rng.index(self.batches.len());
                    let removed = self.batches.swap_remove(index);
                    self.count -= removed.len();
                    for p in removed {
                        self.cut[p] = false;
                    }
                }
            }

            fn output(&self) -> Output {
                Output {
                    cuts: self.batches.iter().flatten().copied().collect(),
                }
            }
        }

        fn complete(input: &Input, state: &mut State, rng: &mut Random) {
            let mut current = components(input, &state.cut);
            // 次のカットがKを超えるまで追加する。構築途中では時間で中断しない。
            loop {
                let Some(vertices) = choose_component(&current, rng) else {
                    continue;
                };
                let (p1, p2) = choose_pair(vertices, rng);
                if p1.dist(&p2) <= MIN_DISTANCE {
                    continue;
                }
                let added = minimum_vertex_cut(input, vertices, p1, p2);
                if state.count + added.len() > Input::K {
                    break;
                }
                state.add(added);
                current = components(input, &state.cut);
            }
        }

        fn accept_candidate(
            state: &mut State,
            score: &mut i64,
            candidate: State,
            candidate_score: i64,
        ) {
            // 悪化した候補は破棄し、削除前の盤面・履歴・本数をそのまま残す。
            if candidate_score >= *score {
                *state = candidate;
                *score = candidate_score;
            }
        }

        pub fn solve(input: &Input, timer: &Timer) -> Output {
            let evaluator = Evaluator::new(input);
            let mut rng = Random::new(42);
            let mut best = Output::default();
            let mut best_score = i64::MIN;
            let mut trials = 0;
            let mut state = State::new();
            let mut current_score = i64::MIN;
            loop {
                let mut candidate = state.clone();
                if trials > 0 {
                    candidate.remove_random_batches(&mut rng);
                }
                complete(input, &mut candidate, &mut rng);
                let score = evaluator.score(&candidate.cut);
                trials += 1;
                if score > best_score {
                    best_score = score;
                    best = candidate.output();
                }
                accept_candidate(&mut state, &mut current_score, candidate, score);
                // 評価完了後だけ時間を判定する。探索用乱数の状態は巻き戻さない。
                if timer.elapsed() > TIME_LIMIT {
                    break;
                }
            }
            eprintln!(
                "trials={trials} estimated_score={best_score} cuts={} elapsed_ms={:.3}",
                best.cuts.len(),
                timer.elapsed().as_secs_f64() * 1000.0
            );
            best
        }

        #[cfg(test)]
        mod tests {
            use super::*;

            fn line_input_with_existing_cuts(count: usize) -> (Input, State) {
                let mut input = Input {
                    d: Map2d::with_default(Input::N),
                };
                for col in 0..Input::N {
                    input.d[Coord::new(0, col)] = 5;
                }
                let existing: Vec<_> = (0..count)
                    .map(|i| Coord::new(2 + i / Input::N, i % Input::N))
                    .collect();
                for &p in &existing {
                    input.d[p] = 1;
                }
                let mut state = State::new();
                state.add(existing);
                (input, state)
            }

            #[test]
            fn continues_after_95_and_adds_a_cut_that_reaches_k() {
                let (input, mut state) = line_input_with_existing_cuts(Input::K - 1);
                complete(&input, &mut state, &mut Random::new(42));
                assert_eq!(state.count, Input::K);
                assert_eq!(state.batches.len(), 2);
                assert_eq!(state.batches[1].len(), 1);
                assert_eq!(state.cut[0].iter().filter(|&&cut| cut).count(), 1);
            }

            #[test]
            fn overflowing_cut_ends_trial_without_changing_state() {
                let (input, mut state) = line_input_with_existing_cuts(Input::K);
                let saved = state.clone();
                complete(&input, &mut state, &mut Random::new(42));
                assert_eq!(state.count, saved.count);
                assert_eq!(state.batches, saved.batches);
                assert!(state.cut.iter().eq(saved.cut.iter()));
            }

            #[test]
            fn worsening_candidate_preserves_state_and_history() {
                let mut state = State::new();
                state.add(vec![Coord::new(0, 0), Coord::new(0, 1)]);
                state.add(vec![Coord::new(1, 0)]);
                let saved = state.clone();
                let mut score = 100;
                let mut candidate = State::new();
                candidate.add(vec![Coord::new(2, 2)]);
                accept_candidate(&mut state, &mut score, candidate, 99);
                assert_eq!(score, 100);
                assert_eq!(state.batches, saved.batches);
                assert_eq!(state.count, saved.count);
                assert!(state.cut.iter().eq(saved.cut.iter()));
            }

            #[test]
            fn equal_and_better_candidates_are_accepted() {
                let mut state = State::new();
                state.add(vec![Coord::new(0, 0)]);
                let mut score = 100;
                for (col, candidate_score) in [(1, 100), (2, 101)] {
                    let mut candidate = State::new();
                    candidate.add(vec![Coord::new(0, col)]);
                    accept_candidate(&mut state, &mut score, candidate, candidate_score);
                    assert_eq!(score, candidate_score);
                    assert_eq!(state.output().cuts, [Coord::new(0, col)]);
                    assert_eq!(state.count, 1);
                    assert_eq!(state.cut.iter().filter(|&&value| value).count(), 1);
                }
            }

            #[test]
            fn components_exclude_low_dryness_and_cut_cells() {
                let mut input = Input {
                    d: Map2d::with_default(Input::N),
                };
                for (col, d) in [5, 9, 4, 5, 5, 9].into_iter().enumerate() {
                    input.d[Coord::new(0, col)] = d;
                }
                let mut cut = Map2d::with_default(Input::N);
                cut[Coord::new(0, 4)] = true;
                let actual = components(&input, &cut);
                assert_eq!(actual.iter().map(Vec::len).collect::<Vec<_>>(), [2, 1, 1]);
                assert_eq!(actual[0], [Coord::new(0, 0), Coord::new(0, 1)]);
            }

            #[test]
            fn terminal_sets_follow_component_detour() {
                let mut input = Input {
                    d: Map2d::from_fn(|_| 5, Input::N),
                };
                let mut vertices = Vec::new();
                for row in 0..16 {
                    vertices.push(Coord::new(row, 0));
                    vertices.push(Coord::new(row, 2));
                }
                let bridge = Coord::new(15, 1);
                vertices.push(bridge);
                input.d[bridge] = 9;
                // 2点のマンハッタン距離は2だが、成分内のBFS距離は32。
                // 成分外の木を通る近道を使わず、両端から距離12の集合を分離する。
                assert_eq!(
                    minimum_vertex_cut(&input, &vertices, Coord::new(0, 0), Coord::new(0, 2)),
                    [bridge]
                );
            }

            #[test]
            fn minimum_cut_may_remove_a_source_vertex() {
                let mut input = Input {
                    d: Map2d::from_fn(|_| 5, Input::N),
                };
                let vertices: Vec<_> = (0..2 * TERMINAL_RADIUS + 4)
                    .map(|col| Coord::new(0, col))
                    .collect();
                // 選択成分外にも木があるが、フローには含めない。
                // sourceの右端を最安にし、その頂点自身を切れることも確認する。
                let cheapest = Coord::new(0, TERMINAL_RADIUS);
                input.d[cheapest] = 9;
                assert_eq!(
                    minimum_vertex_cut(&input, &vertices, vertices[0], *vertices.last().unwrap()),
                    [cheapest]
                );
            }

            #[test]
            fn removing_batches_restores_whole_cuts_and_preserves_best_snapshot() {
                let mut state = State::new();
                for row in 0..8 {
                    state.add((0..row + 1).map(|col| Coord::new(row, col)).collect());
                }
                let best = state.output();
                let mut expected_rng = Random::new(42);
                let expected_count =
                    REMOVE_LOWER + expected_rng.index(REMOVE_UPPER - REMOVE_LOWER + 1);
                state.remove_random_batches(&mut Random::new(42));
                assert_eq!(state.batches.len(), 8 - expected_count);
                assert_eq!(best.cuts.len(), 36);
                assert_eq!(state.count, state.cut.iter().filter(|&&cut| cut).count());
                assert_eq!(state.count, state.output().cuts.len());
                for row in 0..8 {
                    let retained = state.batches.iter().any(|batch| batch[0].row() == row);
                    for col in 0..row + 1 {
                        assert_eq!(state.cut[Coord::new(row, col)], retained);
                    }
                }
            }

            #[test]
            fn removing_more_batches_than_exist_restores_all_trees() {
                let mut state = State::new();
                state.add(vec![Coord::new(0, 0), Coord::new(0, 1)]);
                state.remove_random_batches(&mut Random::new(42));
                assert!(state.batches.is_empty());
                assert_eq!(state.count, 0);
                assert!(!state.cut.iter().any(|&value| value));
                state.remove_random_batches(&mut Random::new(42));
                assert_eq!(state.count, 0);
            }

            #[test]
            fn minimum_cut_cost_matches_exhaustive_search() {
                let mut input = Input {
                    d: Map2d::with_default(Input::N),
                };
                let vertices: Vec<_> = (0..12).map(|i| Coord::new(i / 6, i % 6)).collect();
                for (i, &p) in vertices.iter().enumerate() {
                    input.d[p] = 5 + (i % 5) as u8;
                }
                let p1 = vertices[0];
                let p2 = vertices[11];
                let mut optimum = i64::MAX;
                for mask in 0..(1 << vertices.len()) {
                    let cost: i64 = vertices
                        .iter()
                        .enumerate()
                        .filter(|(i, _)| mask & (1 << i) != 0)
                        .map(|(_, &p)| 10009 - i64::from(input.d[p]))
                        .sum();
                    if cost >= optimum {
                        continue;
                    }
                    let mut seen = vec![false; vertices.len()];
                    let mut stack = Vec::new();
                    for (i, &p) in vertices.iter().enumerate() {
                        if mask & (1 << i) == 0 && p.dist(&p1) <= TERMINAL_RADIUS {
                            seen[i] = true;
                            stack.push(i);
                        }
                    }
                    while let Some(i) = stack.pop() {
                        for (j, &p) in vertices.iter().enumerate() {
                            if mask & (1 << j) == 0 && !seen[j] && vertices[i].dist(&p) == 1 {
                                seen[j] = true;
                                stack.push(j);
                            }
                        }
                    }
                    if !vertices
                        .iter()
                        .enumerate()
                        .any(|(i, &p)| seen[i] && p.dist(&p2) <= TERMINAL_RADIUS)
                    {
                        optimum = cost;
                    }
                }
                let actual = minimum_vertex_cut(&input, &vertices, p1, p2);
                let cost: i64 = actual.iter().map(|&p| 10009 - i64::from(input.d[p])).sum();
                assert_eq!(cost, optimum);
            }
        }
    }

    pub use vertex_cut::solve;
}

fn main() {
    let timer = library::diagnostics::Timer::default();
    let input = problem::Input::read();
    let output = solver::solve(&input, &timer);
    print!("{output}");
}

0