提出 #73751556


ソースコード 拡げる

use std::io::{self, Read};
use std::str::FromStr;
use std::collections::HashMap;

struct Scanner {
    buf: Vec<u8>,
    idx: usize,
}

impl Scanner {
    fn new() -> Self {
        let mut input = String::new();
        io::stdin().read_to_string(&mut input).unwrap();
        Self {
            buf: input.into_bytes(),
            idx: 0,
        }
    }

    fn next<T: FromStr>(&mut self) -> T {
        while self.idx < self.buf.len() && self.buf[self.idx].is_ascii_whitespace() {
            self.idx += 1;
        }
        let start = self.idx;
        while self.idx < self.buf.len() && !self.buf[self.idx].is_ascii_whitespace() {
            self.idx += 1;
        }
        std::str::from_utf8(&self.buf[start..self.idx])
            .unwrap()
            .parse::<T>()
            .ok()
            .unwrap()
    }
}

#[derive(Clone)]
struct RobotPlan {
    i: usize,
    j: usize,
    d: char,
    trans: Vec<(char, usize, char, usize)>,
}

impl RobotPlan {
    fn m(&self) -> usize {
        self.trans.len()
    }
}

#[derive(Clone)]
struct Candidate {
    cost: usize,
    mask: Vec<u64>,
    robot: RobotPlan,
}

fn set_bit(mask: &mut [u64], idx: usize) {
    mask[idx >> 6] |= 1_u64 << (idx & 63);
}

fn count_intersection(a: &[u64], b: &[u64]) -> usize {
    a.iter()
        .zip(b.iter())
        .map(|(&x, &y)| (x & y).count_ones() as usize)
        .sum()
}

fn any_bit(mask: &[u64]) -> bool {
    mask.iter().any(|&x| x != 0)
}

fn for_each_bit(mask: &[u64], mut f: impl FnMut(usize)) {
    for (w, &bits0) in mask.iter().enumerate() {
        let mut bits = bits0;
        while bits != 0 {
            let t = bits.trailing_zeros() as usize;
            f((w << 6) + t);
            bits &= bits - 1;
        }
    }
}

fn splitmix64(mut x: u64) -> u64 {
    x = x.wrapping_add(0x9e3779b97f4a7c15);
    x = (x ^ (x >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
    x = (x ^ (x >> 27)).wrapping_mul(0x94d049bb133111eb);
    x ^ (x >> 31)
}

fn next_rand(state: &mut u64) -> u64 {
    *state = splitmix64(*state);
    *state
}

fn env_usize(name: &str, default: usize) -> usize {
    std::env::var(name)
        .ok()
        .and_then(|s| s.parse::<usize>().ok())
        .unwrap_or(default)
}

fn mask_popcount(mask: &[u64]) -> usize {
    mask.iter().map(|&x| x.count_ones() as usize).sum()
}

fn dir_char(d: usize) -> char {
    match d {
        0 => 'U',
        1 => 'R',
        2 => 'D',
        _ => 'L',
    }
}

fn front_blocked(n: usize, v: &[Vec<u8>], h: &[Vec<u8>], i: usize, j: usize, d: usize) -> bool {
    match d {
        0 => i == 0 || h[i - 1][j] == 1,    // U
        1 => j == n - 1 || v[i][j] == 1,    // R
        2 => i == n - 1 || h[i][j] == 1,    // D
        _ => j == 0 || v[i][j - 1] == 1,    // L
    }
}

fn apply_action(i: usize, j: usize, d: usize, a: char) -> (usize, usize, usize) {
    match a {
        'R' => (i, j, (d + 1) & 3),
        'L' => (i, j, (d + 3) & 3),
        'F' => match d {
            0 => (i - 1, j, d),
            1 => (i, j + 1, d),
            2 => (i + 1, j, d),
            _ => (i, j - 1, d),
        },
        _ => unreachable!(),
    }
}

fn generate_one_state_candidates(
    n: usize,
    v: &[Vec<u8>],
    h: &[Vec<u8>],
    words: usize,
) -> Vec<Candidate> {
    let options = [('F', 'R'), ('F', 'L'), ('R', 'R'), ('R', 'L'), ('L', 'R'), ('L', 'L')];
    let s = n * n * 4;
    let mut out = Vec::new();

    for &(a0, a1) in &options {
        let mut next = vec![0usize; s];
        for node in 0..s {
            let cell = node >> 2;
            let d = node & 3;
            let i = cell / n;
            let j = cell % n;
            let blocked = front_blocked(n, v, h, i, j, d);
            let action = if blocked { a1 } else { a0 };
            let (ni, nj, nd) = apply_action(i, j, d, action);
            next[node] = (((ni * n) + nj) << 2) | nd;
        }

        let mut node_cycle = vec![usize::MAX; s];
        let mut pos = vec![usize::MAX; s];
        let mut cycle_masks: Vec<Vec<u64>> = Vec::new();
        let mut cycle_rep: Vec<usize> = Vec::new();

        for start in 0..s {
            if node_cycle[start] != usize::MAX {
                continue;
            }
            let mut stack: Vec<usize> = Vec::new();
            let mut cur = start;
            while node_cycle[cur] == usize::MAX && pos[cur] == usize::MAX {
                pos[cur] = stack.len();
                stack.push(cur);
                cur = next[cur];
            }

            if node_cycle[cur] != usize::MAX {
                let cid = node_cycle[cur];
                for &u in stack.iter().rev() {
                    node_cycle[u] = cid;
                }
            } else {
                let p = pos[cur];
                let cycle_nodes = &stack[p..];
                let mut mask = vec![0_u64; words];
                for &u in cycle_nodes {
                    set_bit(&mut mask, u >> 2);
                }
                let cid = cycle_masks.len();
                cycle_masks.push(mask);
                cycle_rep.push(cycle_nodes[0]);
                for &u in cycle_nodes {
                    node_cycle[u] = cid;
                }
                for &u in stack[..p].iter().rev() {
                    node_cycle[u] = cid;
                }
            }

            for &u in &stack {
                pos[u] = usize::MAX;
            }
        }

        for cid in 0..cycle_masks.len() {
            let rep = cycle_rep[cid];
            let cell = rep >> 2;
            let d = rep & 3;
            let i = cell / n;
            let j = cell % n;
            out.push(Candidate {
                cost: 1,
                mask: cycle_masks[cid].clone(),
                robot: RobotPlan {
                    i,
                    j,
                    d: dir_char(d),
                    trans: vec![(a0, 0, a1, 0)],
                },
            });
        }
    }

    out
}

fn generate_row_segment_candidates(n: usize, v: &[Vec<u8>], words: usize) -> Vec<Candidate> {
    let mut out = Vec::new();
    for i in 0..n {
        let mut j = 0usize;
        while j < n {
            let start = j;
            let mut mask = vec![0_u64; words];
            set_bit(&mut mask, i * n + j);
            while j + 1 < n && v[i][j] == 0 {
                j += 1;
                set_bit(&mut mask, i * n + j);
            }
            out.push(Candidate {
                cost: 2,
                mask,
                robot: RobotPlan {
                    i,
                    j: start,
                    d: 'R',
                    trans: vec![('F', 0, 'R', 1), ('R', 0, 'R', 0)],
                },
            });
            j += 1;
        }
    }
    out
}

fn generate_col_segment_candidates(n: usize, h: &[Vec<u8>], words: usize) -> Vec<Candidate> {
    let mut out = Vec::new();
    for j in 0..n {
        let mut i = 0usize;
        while i < n {
            let start = i;
            let mut mask = vec![0_u64; words];
            set_bit(&mut mask, i * n + j);
            while i + 1 < n && h[i][j] == 0 {
                i += 1;
                set_bit(&mut mask, i * n + j);
            }
            out.push(Candidate {
                cost: 2,
                mask,
                robot: RobotPlan {
                    i: start,
                    j,
                    d: 'D',
                    trans: vec![('F', 0, 'R', 1), ('R', 0, 'R', 0)],
                },
            });
            i += 1;
        }
    }
    out
}

fn generate_two_state_candidates(
    n: usize,
    v: &[Vec<u8>],
    h: &[Vec<u8>],
    words: usize,
) -> Vec<Candidate> {
    let cells = n * n;
    let s = cells * 4 * 2;
    let a0s = ['F', 'R', 'L'];
    let a1s = ['R', 'L'];

    let mut state_cfgs = Vec::new();
    for &a0 in &a0s {
        for b0 in 0..2 {
            for &a1 in &a1s {
                for b1 in 0..2 {
                    state_cfgs.push((a0, b0, a1, b1));
                }
            }
        }
    }

    let mut out = Vec::new();
    for &c0 in &state_cfgs {
        for &c1 in &state_cfgs {
            let trans = [c0, c1];
            let mut next = vec![0usize; s];
            for node in 0..s {
                let st = node & 1;
                let dir = (node >> 1) & 3;
                let cell = node >> 3;
                let i = cell / n;
                let j = cell % n;
                let wall = front_blocked(n, v, h, i, j, dir);
                let (a, b) = if !wall {
                    (trans[st].0, trans[st].1)
                } else {
                    (trans[st].2, trans[st].3)
                };
                let (ni, nj, nd) = apply_action(i, j, dir, a);
                next[node] = ((((ni * n + nj) << 2) | nd) << 1) | b;
            }

            let mut node_cycle = vec![usize::MAX; s];
            let mut pos = vec![usize::MAX; s];
            let mut cycle_masks: Vec<Vec<u64>> = Vec::new();
            let mut rep_start: Vec<usize> = Vec::new();

            for start in 0..s {
                if node_cycle[start] != usize::MAX {
                    continue;
                }
                let mut stack = Vec::new();
                let mut cur = start;
                while node_cycle[cur] == usize::MAX && pos[cur] == usize::MAX {
                    pos[cur] = stack.len();
                    stack.push(cur);
                    cur = next[cur];
                }
                if node_cycle[cur] != usize::MAX {
                    let cid = node_cycle[cur];
                    for &u in stack.iter().rev() {
                        node_cycle[u] = cid;
                    }
                } else {
                    let p = pos[cur];
                    let mut mask = vec![0_u64; words];
                    for &u in &stack[p..] {
                        set_bit(&mut mask, u >> 3);
                    }
                    let cid = cycle_masks.len();
                    cycle_masks.push(mask);
                    rep_start.push(usize::MAX);
                    for &u in &stack[p..] {
                        node_cycle[u] = cid;
                    }
                    for &u in stack[..p].iter().rev() {
                        node_cycle[u] = cid;
                    }
                }
                for &u in &stack {
                    pos[u] = usize::MAX;
                }
            }

            for cell in 0..cells {
                for d in 0..4 {
                    let node = ((cell << 2) | d) << 1; // internal state = 0
                    let cid = node_cycle[node];
                    if rep_start[cid] == usize::MAX {
                        rep_start[cid] = node;
                    }
                }
            }

            for (cid, &node) in rep_start.iter().enumerate() {
                if node == usize::MAX {
                    continue;
                }
                let cell = node >> 3;
                let d = (node >> 1) & 3;
                let i = cell / n;
                let j = cell % n;
                out.push(Candidate {
                    cost: 2,
                    mask: cycle_masks[cid].clone(),
                    robot: RobotPlan {
                        i,
                        j,
                        d: dir_char(d),
                        trans: vec![
                            (trans[0].0, trans[0].1, trans[0].2, trans[0].3),
                            (trans[1].0, trans[1].1, trans[1].2, trans[1].3),
                        ],
                    },
                });
            }
        }
    }

    out
}

fn generate_random_m_state_candidates(
    n: usize,
    v: &[Vec<u8>],
    h: &[Vec<u8>],
    words: usize,
    m: usize,
    automata_count: usize,
    picks_per_automaton: usize,
    seed: u64,
) -> Vec<Candidate> {
    let cells = n * n;
    let s = cells * 4 * m;
    let a0s = ['F', 'R', 'L'];
    let a1s = ['R', 'L'];
    let mut rng = seed ^ (m as u64).wrapping_mul(0xabc9_8731_55aa_41c7);
    let mut out = Vec::new();

    for _ in 0..automata_count {
        let mut trans = vec![('F', 0usize, 'R', 0usize); m];
        let mut has_f = false;
        for st in 0..m {
            let a0 = a0s[(next_rand(&mut rng) % (a0s.len() as u64)) as usize];
            if a0 == 'F' {
                has_f = true;
            }
            let b0 = (next_rand(&mut rng) % (m as u64)) as usize;
            let a1 = a1s[(next_rand(&mut rng) % (a1s.len() as u64)) as usize];
            let b1 = (next_rand(&mut rng) % (m as u64)) as usize;
            trans[st] = (a0, b0, a1, b1);
        }
        if !has_f {
            continue;
        }

        let mut next = vec![0usize; s];
        for node in 0..s {
            let st = node % m;
            let q = node / m;
            let d = q & 3;
            let cell = q >> 2;
            let i = cell / n;
            let j = cell % n;
            let wall = front_blocked(n, v, h, i, j, d);
            let (a, b) = if !wall {
                (trans[st].0, trans[st].1)
            } else {
                (trans[st].2, trans[st].3)
            };
            let (ni, nj, nd) = apply_action(i, j, d, a);
            next[node] = ((((ni * n + nj) << 2) | nd) * m) + b;
        }

        let mut node_cycle = vec![usize::MAX; s];
        let mut pos = vec![usize::MAX; s];
        let mut cycle_masks: Vec<Vec<u64>> = Vec::new();
        let mut rep_start: Vec<usize> = Vec::new();

        for start in 0..s {
            if node_cycle[start] != usize::MAX {
                continue;
            }
            let mut stack = Vec::new();
            let mut cur = start;
            while node_cycle[cur] == usize::MAX && pos[cur] == usize::MAX {
                pos[cur] = stack.len();
                stack.push(cur);
                cur = next[cur];
            }
            if node_cycle[cur] != usize::MAX {
                let cid = node_cycle[cur];
                for &u in stack.iter().rev() {
                    node_cycle[u] = cid;
                }
            } else {
                let p = pos[cur];
                let mut mask = vec![0_u64; words];
                for &u in &stack[p..] {
                    set_bit(&mut mask, (u / m) >> 2);
                }
                let cid = cycle_masks.len();
                cycle_masks.push(mask);
                rep_start.push(usize::MAX);
                for &u in &stack[p..] {
                    node_cycle[u] = cid;
                }
                for &u in stack[..p].iter().rev() {
                    node_cycle[u] = cid;
                }
            }
            for &u in &stack {
                pos[u] = usize::MAX;
            }
        }

        for cell in 0..cells {
            for d in 0..4 {
                let node = (((cell << 2) | d) * m) + 0;
                let cid = node_cycle[node];
                if rep_start[cid] == usize::MAX {
                    rep_start[cid] = node;
                }
            }
        }

        let mut picks = Vec::new();
        for (cid, &node) in rep_start.iter().enumerate() {
            if node == usize::MAX {
                continue;
            }
            let sz = mask_popcount(&cycle_masks[cid]);
            picks.push((sz, cid, node));
        }
        picks.sort_by_key(|&(sz, _, node)| (std::cmp::Reverse(sz), node));
        picks.truncate(picks_per_automaton);

        for (_, cid, node) in picks {
            let cell = (node / m) >> 2;
            let d = (node / m) & 3;
            let i = cell / n;
            let j = cell % n;
            out.push(Candidate {
                cost: m,
                mask: cycle_masks[cid].clone(),
                robot: RobotPlan {
                    i,
                    j,
                    d: dir_char(d),
                    trans: trans.clone(),
                },
            });
        }
    }

    out
}

fn build_candidate_cells(candidates: &[Candidate], cells: usize) -> Vec<Vec<usize>> {
    let mut out = Vec::with_capacity(candidates.len());
    for c in candidates {
        let mut v = Vec::new();
        for_each_bit(&c.mask, |p| {
            if p < cells {
                v.push(p);
            }
        });
        out.push(v);
    }
    out
}

fn improve_by_add_remove(
    candidates: &[Candidate],
    cand_cells: &[Vec<usize>],
    mut selected: Vec<usize>,
    cells: usize,
) -> Vec<usize> {
    let n = candidates.len();
    let mut sel = vec![false; n];
    for &idx in &selected {
        sel[idx] = true;
    }

    let mut cnt = vec![0_u16; cells];
    for &idx in &selected {
        for &p in &cand_cells[idx] {
            cnt[p] += 1;
        }
    }

    let mut order: Vec<usize> = (0..n).collect();
    order.sort_by_key(|&idx| std::cmp::Reverse(candidates[idx].cost));

    for it in 0..4 {
        let mut best_add = usize::MAX;
        let mut best_removed: Vec<usize> = Vec::new();
        let mut best_delta = 0_i32;

        let mut add_order: Vec<usize> = (0..n).filter(|&idx| !sel[idx]).collect();
        add_order.sort_by_key(|&idx| splitmix64((it as u64) ^ ((idx as u64) * 0x9e3779b97f4a7c15)));
        for &add_idx in add_order.iter().take(1024) {
            if sel[add_idx] {
                continue;
            }
            let mut cnt2 = cnt.clone();
            for &p in &cand_cells[add_idx] {
                cnt2[p] += 1;
            }
            let mut removed = Vec::new();
            let mut removed_cost = 0_i32;

            for &idx in &order {
                if !sel[idx] {
                    continue;
                }
                let mut ok = true;
                for &p in &cand_cells[idx] {
                    if cnt2[p] <= 1 {
                        ok = false;
                        break;
                    }
                }
                if ok {
                    for &p in &cand_cells[idx] {
                        cnt2[p] -= 1;
                    }
                    removed.push(idx);
                    removed_cost += candidates[idx].cost as i32;
                }
            }

            let delta = candidates[add_idx].cost as i32 - removed_cost;
            if delta < best_delta {
                best_delta = delta;
                best_add = add_idx;
                best_removed = removed;
            }
        }

        if best_add == usize::MAX {
            break;
        }

        sel[best_add] = true;
        for &p in &cand_cells[best_add] {
            cnt[p] += 1;
        }
        selected.push(best_add);

        for &idx in &best_removed {
            if !sel[idx] {
                continue;
            }
            sel[idx] = false;
            for &p in &cand_cells[idx] {
                cnt[p] -= 1;
            }
        }
        selected.retain(|&idx| sel[idx]);
    }

    selected
}

fn improve_by_drop_repair(
    candidates: &[Candidate],
    cand_cells: &[Vec<usize>],
    selected: Vec<usize>,
    cells: usize,
    seed: u64,
    passes: usize,
) -> Vec<usize> {
    let n = candidates.len();
    let mut sel = vec![false; n];
    for &idx in &selected {
        sel[idx] = true;
    }
    let mut cnt = vec![0_u16; cells];
    let mut cost: i32 = 0;
    for &idx in &selected {
        cost += candidates[idx].cost as i32;
        for &p in &cand_cells[idx] {
            cnt[p] += 1;
        }
    }

    for pass in 0..(passes as u64) {
        let mut sel_list: Vec<usize> = (0..n).filter(|&idx| sel[idx]).collect();
        sel_list.sort_by_key(|&idx| {
            (
                std::cmp::Reverse(candidates[idx].cost),
                splitmix64(seed ^ pass ^ ((idx as u64) * 0x9e3779b97f4a7c15)),
            )
        });
        let mut improved = false;

        for rm in sel_list {
            let mut lsel = sel.clone();
            let mut lcnt = cnt.clone();
            let mut lcost = cost;
            lsel[rm] = false;
            lcost -= candidates[rm].cost as i32;
            for &p in &cand_cells[rm] {
                lcnt[p] -= 1;
            }

            let mut uncovered = 0usize;
            for &x in &lcnt {
                if x == 0 {
                    uncovered += 1;
                }
            }
            if uncovered == 0 && lcost < cost {
                sel = lsel;
                cnt = lcnt;
                cost = lcost;
                improved = true;
                break;
            }

            while uncovered > 0 && lcost < cost {
                let mut best_idx = usize::MAX;
                let mut best_gain = 0usize;
                let mut best_cost = 1usize;
                let mut best_key = u64::MAX;

                for idx in 0..n {
                    if lsel[idx] {
                        continue;
                    }
                    let mut gain = 0usize;
                    for &p in &cand_cells[idx] {
                        if lcnt[p] == 0 {
                            gain += 1;
                        }
                    }
                    if gain == 0 {
                        continue;
                    }
                    let c = candidates[idx].cost;
                    let key = splitmix64(seed ^ pass ^ ((idx as u64) * 0xbf58476d1ce4e5b9));
                    let better = if best_idx == usize::MAX {
                        true
                    } else {
                        let lhs = gain * best_cost;
                        let rhs = best_gain * c;
                        lhs > rhs
                            || (lhs == rhs
                                && (gain > best_gain
                                    || (gain == best_gain
                                        && (c < best_cost || (c == best_cost && key < best_key)))))
                    };
                    if better {
                        best_idx = idx;
                        best_gain = gain;
                        best_cost = c;
                        best_key = key;
                    }
                }

                if best_idx == usize::MAX {
                    break;
                }
                lsel[best_idx] = true;
                lcost += candidates[best_idx].cost as i32;
                for &p in &cand_cells[best_idx] {
                    if lcnt[p] == 0 {
                        uncovered -= 1;
                    }
                    lcnt[p] += 1;
                }
            }

            if uncovered == 0 && lcost < cost {
                sel = lsel;
                cnt = lcnt;
                cost = lcost;
                improved = true;
                break;
            }
        }

        if !improved {
            break;
        }
    }

    (0..n).filter(|&idx| sel[idx]).collect()
}

fn dedup_candidates(candidates: Vec<Candidate>) -> Vec<Candidate> {
    let mut out: Vec<Candidate> = Vec::new();
    let mut pos: HashMap<Vec<u64>, usize> = HashMap::new();
    for c in candidates {
        if let Some(&idx) = pos.get(&c.mask) {
            if c.cost < out[idx].cost {
                out[idx] = c;
            }
        } else {
            let idx = out.len();
            pos.insert(c.mask.clone(), idx);
            out.push(c);
        }
    }
    out
}

fn solve_weighted_cover(candidates: &[Candidate], cells: usize, seed: u64) -> Vec<usize> {
    let words = (cells + 63) >> 6;
    let mut uncovered = vec![!0_u64; words];
    if cells & 63 != 0 {
        uncovered[words - 1] = (1_u64 << (cells & 63)) - 1;
    }

    let mut used = vec![false; candidates.len()];
    let mut selected: Vec<usize> = Vec::new();

    while any_bit(&uncovered) {
        let mut best_idx = usize::MAX;
        let mut best_gain = 0usize;
        let mut best_cost = 1usize;
        let mut best_key = u64::MAX;

        for (idx, c) in candidates.iter().enumerate() {
            if used[idx] {
                continue;
            }
            let gain = count_intersection(&c.mask, &uncovered);
            if gain == 0 {
                continue;
            }
            let better = if best_idx == usize::MAX {
                true
            } else {
                let lhs = gain * best_cost;
                let rhs = best_gain * c.cost;
                let key = splitmix64(seed ^ (idx as u64).wrapping_mul(0x9e3779b97f4a7c15));
                lhs > rhs
                    || (lhs == rhs
                        && (gain > best_gain
                            || (gain == best_gain
                                && (c.cost < best_cost
                                    || (c.cost == best_cost && key < best_key)))))
            };
            if better {
                best_idx = idx;
                best_gain = gain;
                best_cost = c.cost;
                best_key = splitmix64(seed ^ (idx as u64).wrapping_mul(0x9e3779b97f4a7c15));
            }
        }

        if best_idx == usize::MAX {
            break;
        }
        used[best_idx] = true;
        selected.push(best_idx);
        for (u, &m) in uncovered.iter_mut().zip(candidates[best_idx].mask.iter()) {
            *u &= !m;
        }
    }

    let mut cnt = vec![0_u16; cells];
    for &idx in &selected {
        for_each_bit(&candidates[idx].mask, |p| {
            if p < cells {
                cnt[p] += 1;
            }
        });
    }

    let mut active = vec![true; selected.len()];
    loop {
        let mut changed = false;
        for t in (0..selected.len()).rev() {
            if !active[t] {
                continue;
            }
            let idx = selected[t];
            let mut removable = true;
            for_each_bit(&candidates[idx].mask, |p| {
                if p < cells && cnt[p] <= 1 {
                    removable = false;
                }
            });
            if removable {
                active[t] = false;
                changed = true;
                for_each_bit(&candidates[idx].mask, |p| {
                    if p < cells {
                        cnt[p] -= 1;
                    }
                });
            }
        }
        if !changed {
            break;
        }
    }

    let mut out = Vec::new();
    for (t, &idx) in selected.iter().enumerate() {
        if active[t] {
            out.push(idx);
        }
    }
    out
}

fn main() {
    let mut sc = Scanner::new();

    let n: usize = sc.next();
    let _ak: i64 = sc.next();
    let _am: i64 = sc.next();
    let _aw: i64 = sc.next();

    let mut v = vec![vec![0_u8; n - 1]; n];
    for row in &mut v {
        let s: String = sc.next();
        for (j, &b) in s.as_bytes().iter().enumerate() {
            row[j] = (b == b'1') as u8;
        }
    }
    let mut h = vec![vec![0_u8; n]; n - 1];
    for row in &mut h {
        let s: String = sc.next();
        for (j, &b) in s.as_bytes().iter().enumerate() {
            row[j] = (b == b'1') as u8;
        }
    }

    let cells = n * n;
    let words = (cells + 63) >> 6;

    let mut seed_base = 0x1234_5678_9abc_def0_u64 ^ (n as u64);
    for row in &v {
        for &x in row {
            seed_base = splitmix64(seed_base ^ (x as u64 + 1));
        }
    }
    for row in &h {
        for &x in row {
            seed_base = splitmix64(seed_base ^ (x as u64 + 3));
        }
    }

    let mut candidates = generate_one_state_candidates(n, &v, &h, words);
    let row_candidates = generate_row_segment_candidates(n, &v, words);
    let col_candidates = generate_col_segment_candidates(n, &h, words);
    let two_state_candidates = generate_two_state_candidates(n, &v, &h, words);
    let c3 = env_usize("C3_AUT", 768);
    let p3 = env_usize("C3_PICK", 12);
    let c4 = env_usize("C4_AUT", 512);
    let p4 = env_usize("C4_PICK", 10);
    let c5 = env_usize("C5_AUT", 256);
    let p5 = env_usize("C5_PICK", 8);
    let c6 = env_usize("C6_AUT", 512);
    let p6 = env_usize("C6_PICK", 8);
    let c7 = env_usize("C7_AUT", 256);
    let p7 = env_usize("C7_PICK", 6);
    let c8 = env_usize("C8_AUT", 96);
    let p8 = env_usize("C8_PICK", 5);
    let c9 = env_usize("C9_AUT", 192);
    let p9 = env_usize("C9_PICK", 5);
    let c12 = env_usize("C12_AUT", 96);
    let p12 = env_usize("C12_PICK", 4);
    let c15 = env_usize("C15_AUT", 64);
    let p15 = env_usize("C15_PICK", 3);
    let three_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 3, c3, p3, seed_base ^ 0x1357_9bdf);
    let four_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 4, c4, p4, seed_base ^ 0x2468_ace0);
    let five_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 5, c5, p5, seed_base ^ 0x3141_5926);
    let six_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 6, c6, p6, seed_base ^ 0x2718_2818);
    let seven_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 7, c7, p7, seed_base ^ 0x1618_0339);
    let eight_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 8, c8, p8, seed_base ^ 0x5772_1566);
    let nine_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 9, c9, p9, seed_base ^ 0x1414_2135);
    let twelve_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 12, c12, p12, seed_base ^ 0x1234_4321);
    let fifteen_state_candidates =
        generate_random_m_state_candidates(n, &v, &h, words, 15, c15, p15, seed_base ^ 0x0f0f_a5a5);
    candidates.extend(row_candidates.clone());
    candidates.extend(col_candidates.clone());
    candidates.extend(two_state_candidates);
    candidates.extend(three_state_candidates);
    candidates.extend(four_state_candidates);
    candidates.extend(five_state_candidates);
    candidates.extend(six_state_candidates);
    candidates.extend(seven_state_candidates);
    candidates.extend(eight_state_candidates);
    candidates.extend(nine_state_candidates);
    candidates.extend(twelve_state_candidates);
    candidates.extend(fifteen_state_candidates);
    candidates = dedup_candidates(candidates);
    let cand_cells = build_candidate_cells(&candidates, cells);

    let mut best_selected = solve_weighted_cover(&candidates, cells, seed_base);
    let starts = env_usize("START_TRIALS", 20).max(1);
    let drop_passes = env_usize("DROP_PASSES", 4).max(1);
    best_selected = improve_by_add_remove(&candidates, &cand_cells, best_selected, cells);
    let mut best_m: usize = best_selected.iter().map(|&idx| candidates[idx].cost).sum();
    for t in 1_u64..(starts as u64) {
        let selected = solve_weighted_cover(&candidates, cells, seed_base ^ splitmix64(t));
        let selected = improve_by_add_remove(&candidates, &cand_cells, selected, cells);
        let m: usize = selected.iter().map(|&idx| candidates[idx].cost).sum();
        if m < best_m {
            best_m = m;
            best_selected = selected;
        }
    }
    best_selected = improve_by_drop_repair(
        &candidates,
        &cand_cells,
        best_selected,
        cells,
        seed_base,
        drop_passes,
    );

    let mut robots: Vec<RobotPlan> = best_selected
        .iter()
        .map(|&idx| candidates[idx].robot.clone())
        .collect();
    let mut m_sum: usize = robots.iter().map(RobotPlan::m).sum();

    let mut row_baseline: Vec<RobotPlan> = row_candidates.iter().map(|c| c.robot.clone()).collect();
    let mut col_baseline: Vec<RobotPlan> = col_candidates.iter().map(|c| c.robot.clone()).collect();
    let row_m: usize = row_baseline.iter().map(RobotPlan::m).sum();
    let col_m: usize = col_baseline.iter().map(RobotPlan::m).sum();
    let baseline = if row_m <= col_m {
        (&mut row_baseline, row_m)
    } else {
        (&mut col_baseline, col_m)
    };

    if m_sum > baseline.1 {
        robots = baseline.0.clone();
        m_sum = baseline.1;
    }

    if robots.is_empty() {
        robots.push(RobotPlan {
            i: 0,
            j: 0,
            d: 'U',
            trans: vec![('R', 0, 'R', 0)],
        });
        m_sum = 1;
    }

    let _ = m_sum;
    println!("{}", robots.len());
    for rb in &robots {
        println!("{} {} {} {}", rb.m(), rb.i, rb.j, rb.d);
        for &(a0, b0, a1, b1) in &rb.trans {
            println!("{} {} {} {}", a0, b0, a1, b1);
        }
    }

    let z1 = "0".repeat(n.saturating_sub(1));
    for _ in 0..n {
        println!("{}", z1);
    }
    let z2 = "0".repeat(n);
    for _ in 0..n.saturating_sub(1) {
        println!("{}", z2);
    }
}

提出情報

提出日時
問題 A - Periodic Patrol Automata (A)
ユーザ rho_aias
言語 Rust (rustc 1.89.0)
得点 628034695
コード長 32342 Byte
結果 AC
実行時間 702 ms
メモリ 66328 KiB

ジャッジ結果

セット名 test_ALL
得点 / 配点 628034695 / 15000000000
結果
AC × 150
セット名 テストケース
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
ケース名 結果 実行時間 メモリ
test_0000.txt AC 577 ms 62780 KiB
test_0001.txt AC 546 ms 64056 KiB
test_0002.txt AC 577 ms 63096 KiB
test_0003.txt AC 700 ms 62960 KiB
test_0004.txt AC 550 ms 64044 KiB
test_0005.txt AC 602 ms 65376 KiB
test_0006.txt AC 551 ms 63176 KiB
test_0007.txt AC 566 ms 63264 KiB
test_0008.txt AC 684 ms 63424 KiB
test_0009.txt AC 555 ms 63696 KiB
test_0010.txt AC 636 ms 62928 KiB
test_0011.txt AC 543 ms 64500 KiB
test_0012.txt AC 552 ms 64180 KiB
test_0013.txt AC 549 ms 64256 KiB
test_0014.txt AC 558 ms 65584 KiB
test_0015.txt AC 617 ms 63480 KiB
test_0016.txt AC 584 ms 64312 KiB
test_0017.txt AC 615 ms 64032 KiB
test_0018.txt AC 576 ms 62624 KiB
test_0019.txt AC 702 ms 63532 KiB
test_0020.txt AC 590 ms 65036 KiB
test_0021.txt AC 545 ms 63884 KiB
test_0022.txt AC 666 ms 60812 KiB
test_0023.txt AC 547 ms 64256 KiB
test_0024.txt AC 566 ms 63020 KiB
test_0025.txt AC 565 ms 65132 KiB
test_0026.txt AC 701 ms 64212 KiB
test_0027.txt AC 559 ms 64236 KiB
test_0028.txt AC 618 ms 63572 KiB
test_0029.txt AC 558 ms 64176 KiB
test_0030.txt AC 549 ms 63268 KiB
test_0031.txt AC 574 ms 63296 KiB
test_0032.txt AC 538 ms 64424 KiB
test_0033.txt AC 572 ms 63324 KiB
test_0034.txt AC 600 ms 63464 KiB
test_0035.txt AC 596 ms 62504 KiB
test_0036.txt AC 563 ms 62976 KiB
test_0037.txt AC 595 ms 65604 KiB
test_0038.txt AC 580 ms 63216 KiB
test_0039.txt AC 558 ms 64988 KiB
test_0040.txt AC 648 ms 64460 KiB
test_0041.txt AC 546 ms 65596 KiB
test_0042.txt AC 602 ms 64108 KiB
test_0043.txt AC 615 ms 64516 KiB
test_0044.txt AC 574 ms 64328 KiB
test_0045.txt AC 583 ms 65380 KiB
test_0046.txt AC 582 ms 63208 KiB
test_0047.txt AC 558 ms 64056 KiB
test_0048.txt AC 560 ms 63244 KiB
test_0049.txt AC 565 ms 63104 KiB
test_0050.txt AC 579 ms 62916 KiB
test_0051.txt AC 560 ms 63896 KiB
test_0052.txt AC 624 ms 63568 KiB
test_0053.txt AC 551 ms 64316 KiB
test_0054.txt AC 549 ms 63092 KiB
test_0055.txt AC 618 ms 63276 KiB
test_0056.txt AC 535 ms 64424 KiB
test_0057.txt AC 546 ms 64128 KiB
test_0058.txt AC 631 ms 63188 KiB
test_0059.txt AC 608 ms 65412 KiB
test_0060.txt AC 567 ms 63784 KiB
test_0061.txt AC 544 ms 64652 KiB
test_0062.txt AC 537 ms 64420 KiB
test_0063.txt AC 633 ms 61716 KiB
test_0064.txt AC 557 ms 64980 KiB
test_0065.txt AC 558 ms 64624 KiB
test_0066.txt AC 553 ms 62596 KiB
test_0067.txt AC 556 ms 63256 KiB
test_0068.txt AC 616 ms 64556 KiB
test_0069.txt AC 623 ms 62260 KiB
test_0070.txt AC 563 ms 62468 KiB
test_0071.txt AC 612 ms 63752 KiB
test_0072.txt AC 551 ms 64200 KiB
test_0073.txt AC 577 ms 64048 KiB
test_0074.txt AC 556 ms 64580 KiB
test_0075.txt AC 582 ms 64532 KiB
test_0076.txt AC 683 ms 64660 KiB
test_0077.txt AC 556 ms 62528 KiB
test_0078.txt AC 611 ms 65152 KiB
test_0079.txt AC 566 ms 63904 KiB
test_0080.txt AC 560 ms 63072 KiB
test_0081.txt AC 531 ms 64912 KiB
test_0082.txt AC 542 ms 63620 KiB
test_0083.txt AC 584 ms 65276 KiB
test_0084.txt AC 561 ms 63572 KiB
test_0085.txt AC 643 ms 65076 KiB
test_0086.txt AC 549 ms 64088 KiB
test_0087.txt AC 584 ms 63772 KiB
test_0088.txt AC 614 ms 65160 KiB
test_0089.txt AC 542 ms 65308 KiB
test_0090.txt AC 605 ms 63968 KiB
test_0091.txt AC 554 ms 64280 KiB
test_0092.txt AC 570 ms 64712 KiB
test_0093.txt AC 606 ms 63932 KiB
test_0094.txt AC 584 ms 64300 KiB
test_0095.txt AC 618 ms 62764 KiB
test_0096.txt AC 549 ms 64032 KiB
test_0097.txt AC 594 ms 64504 KiB
test_0098.txt AC 567 ms 65340 KiB
test_0099.txt AC 563 ms 64928 KiB
test_0100.txt AC 580 ms 64964 KiB
test_0101.txt AC 562 ms 64924 KiB
test_0102.txt AC 573 ms 64688 KiB
test_0103.txt AC 541 ms 66328 KiB
test_0104.txt AC 534 ms 64568 KiB
test_0105.txt AC 567 ms 63324 KiB
test_0106.txt AC 565 ms 63536 KiB
test_0107.txt AC 561 ms 64344 KiB
test_0108.txt AC 549 ms 63912 KiB
test_0109.txt AC 579 ms 64124 KiB
test_0110.txt AC 596 ms 65004 KiB
test_0111.txt AC 562 ms 64728 KiB
test_0112.txt AC 541 ms 64324 KiB
test_0113.txt AC 538 ms 64432 KiB
test_0114.txt AC 627 ms 64916 KiB
test_0115.txt AC 619 ms 65028 KiB
test_0116.txt AC 550 ms 63888 KiB
test_0117.txt AC 591 ms 63920 KiB
test_0118.txt AC 665 ms 62268 KiB
test_0119.txt AC 550 ms 64460 KiB
test_0120.txt AC 611 ms 63928 KiB
test_0121.txt AC 618 ms 64508 KiB
test_0122.txt AC 630 ms 63200 KiB
test_0123.txt AC 556 ms 63180 KiB
test_0124.txt AC 554 ms 63584 KiB
test_0125.txt AC 555 ms 64752 KiB
test_0126.txt AC 558 ms 64372 KiB
test_0127.txt AC 545 ms 65040 KiB
test_0128.txt AC 583 ms 63320 KiB
test_0129.txt AC 551 ms 64308 KiB
test_0130.txt AC 566 ms 64356 KiB
test_0131.txt AC 533 ms 65756 KiB
test_0132.txt AC 551 ms 65404 KiB
test_0133.txt AC 553 ms 62112 KiB
test_0134.txt AC 579 ms 65996 KiB
test_0135.txt AC 601 ms 62792 KiB
test_0136.txt AC 546 ms 65148 KiB
test_0137.txt AC 583 ms 64932 KiB
test_0138.txt AC 548 ms 64104 KiB
test_0139.txt AC 587 ms 65192 KiB
test_0140.txt AC 565 ms 65356 KiB
test_0141.txt AC 552 ms 63688 KiB
test_0142.txt AC 546 ms 65504 KiB
test_0143.txt AC 561 ms 63440 KiB
test_0144.txt AC 560 ms 64908 KiB
test_0145.txt AC 546 ms 64344 KiB
test_0146.txt AC 547 ms 65332 KiB
test_0147.txt AC 605 ms 63032 KiB
test_0148.txt AC 554 ms 64312 KiB
test_0149.txt AC 559 ms 63728 KiB