Module d

Expand description

§ABC 407 D - Domino Covering XOR

refs: https://atcoder.jp/contests/abc407/tasks/abc407_d

マス目が最大でも 20 個までしか存在せず, 全探索で間に合う.

use std::ops::BitXor;

use proconio::input;

#[derive(Copy, Clone)]
struct Point {
    h: usize,
    w: usize,
    x: usize,
    y: usize,
}

impl Point {
    fn next(&self) -> Self {
        if self.has_next_x() {
            Self {
                x: self.x + 1,
                y: self.y,
                ..*self
            }
        } else if self.has_next_y() {
            Self {
                x: 0,
                y: self.y + 1,
                ..*self
            }
        } else {
            *self
        }
    }

    fn is_terminal(&self) -> bool {
        self.x == self.h - 1 && self.y == self.w - 1
    }

    fn has_next_x(&self) -> bool {
        self.x < self.h - 1
    }

    fn has_next_y(&self) -> bool {
        self.y < self.w - 1
    }
}

struct Field {
    has_domino: Vec<Vec<bool>>,
    score: Vec<Vec<usize>>,
}

impl Field {
    fn new(score: Vec<Vec<usize>>) -> Self {
        let (h, w) = Self::dimension(&score);
        let has_domino = vec![vec![false; w]; h];

        Self { score, has_domino }
    }

    fn put_x_domino(&mut self, p: &Point) {
        self.has_domino[p.x][p.y] = true;
        self.has_domino[p.x + 1][p.y] = true;
    }

    fn put_y_domino(&mut self, p: &Point) {
        self.has_domino[p.x][p.y] = true;
        self.has_domino[p.x][p.y + 1] = true;
    }

    fn remove_x_domino(&mut self, p: &Point) {
        self.has_domino[p.x][p.y] = false;
        self.has_domino[p.x + 1][p.y] = false;
    }

    fn remove_y_domino(&mut self, p: &Point) {
        self.has_domino[p.x][p.y] = false;
        self.has_domino[p.x][p.y + 1] = false;
    }

    fn calc(&self) -> usize {
        let (h, w) = Self::dimension(&self.has_domino);

        let mut score = 0;
        for x in 0..h {
            for y in 0..w {
                if !self.has_domino[x][y] {
                    score = score.bitxor(self.score[x][y]);
                }
            }
        }

        score
    }

    fn dimension<T>(field: &[Vec<T>]) -> (usize, usize) {
        (field.len(), field[0].len())
    }
}

fn main() {
    input! {
        h: usize, w: usize,
        a: [[usize; w]; h],
    }

    let mut field = Field::new(a);
    let start = Point { h, w, x: 0, y: 0 };

    let ans = dfs(start, &mut field);

    println!("{ans}");
}

fn dfs(p: Point, field: &mut Field) -> usize {
    if p.is_terminal() {
        return field.calc();
    }

    let mut score = 0;
    let has_domino = field.has_domino[p.x][p.y];
    // 縦に置く
    if !has_domino && p.has_next_x() && !field.has_domino[p.x + 1][p.y] {
        field.put_x_domino(&p);
        score = score.max(dfs(p.next(), field));
        field.remove_x_domino(&p);
    }

    // 横に置く
    if !has_domino && p.has_next_y() && !field.has_domino[p.x][p.y + 1] {
        field.put_y_domino(&p);
        score = score.max(dfs(p.next(), field));
        field.remove_y_domino(&p);
    }

    // 置かない
    score = score.max(dfs(p.next(), field));

    score
}