Problem:
座席 (Seats)　

問題文

2XXX 年，世界の国は直線状に並んでいた．N 個の国があり，1, 2, ..., N の番号が付けられている．i = 1, 2, ..., N - 1 に対し，国 i と国 i + 1 が互いに隣国である．

この年の国際情報オリンピックでは，国 i からは A_i 人の選手が参加する．国際情報オリンピックの技術委員のあなたは，競技での座席表を作成する担当である．競技会場が細長いため，一列に並んだ A_1 + A_2 + ... + A_N 個の座席に選手たちを割り当てることになった．不正防止のため，同じ国の選手や隣国の選手を隣り合う席に割り当ててはならない．

選手たちを座席に割り当てる方法は何通りあるだろうか．この数は非常に大きくなる可能性があるので，それを 10007 で割った余りを求めたい．

制約

1 ≦ N ≦ 100

1 ≦ A_i ≦ 4 (1 ≦ i ≦ N)

入力・出力

入力

入力は以下の形式で標準入力から与えられる．

N

A_1 A_2 ... A_N

出力

選手たちを座席に割り当てる方法の数を 10007 で割った余りを 1 行で出力せよ．

入出力例

入力例 1

4
2 1 1 1

出力例 1

4

国 1 から参加する 2 人の選手を 1 と 1'，国 2 から参加する 1 人の選手を 2，国 3 から参加する 1 人の選手を 3，国 4 から参加する 1 人の選手を 4 で表すことにすると，選手たちを座席に割り当てる方法としては，以下の 4 通りの並べ方が考えられる：

1, 3, 1', 4, 2

1', 3, 1, 4, 2

2, 4, 1, 3, 1'

2, 4, 1', 3, 1

入力例 2

5
1 2 3 2 1

出力例 2

0

この入力例では，条件を満たす座席表は存在しない．

入力例 3

6
1 2 3 3 2 1

出力例 2

4754

この入力例では，選手たちを座席に割り当てる方法は 24768 通りあるため，それを 10007 で割った余りである 4754 を出力する．

情報オリンピック日本委員会作 『第 18 回日本情報オリンピック JOI 2018/2019 予選競技課題』

Solution in Rust (judge verdict: Accepted)

extern crate core;

use std::fmt;
use std::cmp::{Ordering, min, max};
use std::fmt::{Display, Error, Formatter};
use std::f32::MAX;

fn show<T: Display>(vec: &Vec<T>) {
    if vec.is_empty() {
        println!("[]");
    }else {
        print!("[{}", vec[0]);
        for i in 1 .. vec.len() {
            print!(", {}", vec[i]);
        }
        println!("]");
    }
}
macro_rules! read_line{
    () => {{
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).ok();
        line
    }};
    (delimiter: ' ') => {
        read_line!().split_whitespace().map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (delimiter: $p:expr) => {
        read_line!().split($p).map(|x|x.to_string()).collect::<Vec<_>>()
    };
    (' ') => {
        read_line!(delimiter: ' ')
    };
    ($delimiter:expr) => {
        read_line!(delimiter: $delimiter)
    };
    (' '; $ty:ty) => {
        read_line!().split_whitespace().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
    ($delimiter:expr; $ty:ty) => {
        read_line!($delimiter).into_iter().map(|x|x.parse::<$ty>().ok().unwrap()).collect::<Vec<$ty>>()
    };
}
macro_rules! let_all {
    ($($n:ident:$t:ty),*) => {
        let line = read_line!(delimiter: ' ');
        let mut iter = line.iter();
        $(let $n:$t = iter.next().unwrap().parse().ok().unwrap();)*
    };
}

fn main() {
    let_all!(n: usize);
    let countries = read_line!(' '; i32);
    let mut sum = 0;
    for &a in &countries {
        sum += a;
    }
    let mut memo = vec![vec![vec![vec![vec![-1_i64; n];4 * n + 2];9];8];4];
    println!("{}", solve(0, 0, 0, 0, 0, &countries, 1, &Factorial::new(4 * n + 1), &mut memo, sum));
}
const MOD: i64 = 10007;
fn solve(prev_same: i32, prev_neighbor: i32, prev_other: i32, neighbor: i32, current: usize, countries: &Vec<i32>, whole: i32, factorial: &Factorial, memo: &mut Vec<Vec<Vec<Vec<Vec<i64>>>>>, rest_player: i32) -> i64 {
    if current == countries.len() {
        //println!("prev same {}, prev neighbor {}, prev other {}, neighbor {}, current {}, whole {}", prev_same, prev_neighbor, prev_other, neighbor, current, whole);
        if prev_same == 0 && prev_neighbor == 0 && neighbor == 0 {
            1
        } else {
            0
        }
    }else if prev_same + prev_neighbor + neighbor > rest_player {
        0
    }else {
        match memo[prev_same as usize][prev_neighbor as usize][prev_other as usize][neighbor as usize][current] {
            -1 => {
                //println!("prev same {}, prev neighbor {}, prev other {}, neighbor {}, current {}, whole {}", prev_same, prev_neighbor, prev_other, neighbor, current, whole);
                let mut res = 0_i64;
                let rest_space = whole - prev_same - prev_neighbor - prev_other - neighbor;
                let c = factorial.factorial(countries[current]);
                for i in 0 .. if prev_same > 0 {countries[current] + 1} else {1} {
                    for di in max(i - prev_same, 0) .. max(i, 1) {
                        let si = i - di;
                        let ci = if i == 0 {c}else {c * factorial.combination(i - 1, si - 1) * factorial.combination(prev_same, si) % MOD };
                        for j in 0 .. if prev_neighbor > 0 { countries[current] - i + 1 } else { 1 } {
                            for dj in max(j - prev_neighbor, 0) .. max(j, 1) {
                                let sj = j - dj;
                                let cj = if j == 0 {ci} else {ci * factorial.combination(j - 1, sj - 1) * factorial.combination(prev_neighbor, sj) % MOD };
                                for k in 0 .. if prev_other > 0 { countries[current] - i - j + 1 } else { 1 } {
                                    for dk in max(k - prev_other, 0) .. max(k, 1) {
                                        let sk = k - dk;
                                        let ck = if k == 0 {cj} else {cj * factorial.combination(k - 1, sk - 1) * factorial.combination(prev_other, sk) % MOD };
                                        for l in 0 .. if neighbor > 0 { countries[current] - i - j - k + 1 } else { 1 } {
                                            for dl in max(l - neighbor, 0) .. max(l, 1) {
                                                let sl = l - dl;
                                                let cl = if l == 0 {ck} else {ck * factorial.combination(l - 1, sl - 1) * factorial.combination(neighbor, sl) % MOD };
                                                let rest = countries[current] - i - j - k - l;
                                                for dr in max(rest - rest_space, 0) .. max(rest, 1) {
                                                    let sr = rest - dr;
                                                    let cr = if rest == 0 {cl} else {cl * factorial.combination(rest - 1, sr - 1) * factorial.combination(rest_space, sr) % MOD };
                                                    let new_same = di + dj + dk + dl + dr;
                                                    let new_prev_neighbor = si * 2 + sj + sk;
                                                    let new_other = sj + sk + sl * 2 + sr * 2;
                                                    let new_neighbor = prev_same - si + prev_neighbor - sj + neighbor - sl;
                                                    res += solve(new_same, new_prev_neighbor, new_other, new_neighbor, current + 1, countries, whole + countries[current], factorial, memo, rest_player - countries[current]) * cr;
                                                    res %= MOD;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                memo[prev_same as usize][prev_neighbor as usize][prev_other as usize][neighbor as usize][current] = res;
                res
            }
            cache => cache,
        }
    }
}
pub struct Factorial {
    memo: Vec<i64>,
    inverse_memo: Vec<i64>,
}
impl Factorial {
    fn new(max: usize) -> Factorial {
        let mut f = vec![1_i64; max + 1];
        for i in 1 .. f.len() {
            f[i] = f[i - 1] * i as i64 % MOD;
        }
        let mut inv = vec![1_i64; max + 1];
        for i in 2 .. inv.len() {
            inv[i] = inv[(MOD % i as i64) as usize] * (MOD - MOD / i as i64) % MOD;
        }
        let mut inv_fact = vec![1_i64; max + 1];
        for i in 2 .. inv_fact.len() {
            inv_fact[i] = inv_fact[i - 1] * inv[i] % MOD;
        }
        Factorial{memo: f, inverse_memo: inv_fact}
    }
    fn factorial(&self, n: i32) -> i64 {
        self.memo[n as usize]
    }
    fn combination(&self, n: i32, r: i32) -> i64 {
        self.memo[n as usize] * self.inverse_memo[(n - r) as usize] * self.inverse_memo[r as usize] % MOD
    }
}