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 C (judge verdict: Accepted)

#include <stdio.h>
#define NMAX 100
#define AMAX 4
#define MOD 10007
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int main(void)
{
  int i, j, k, l, m, J, K, L, M, x, n, a, prea = 0, s = 0;
  int binom[NMAX*AMAX+1][NMAX*AMAX+1] = {0}, dp[NMAX+1][NMAX*AMAX+1][AMAX*2][AMAX] = {0};
  for (i = 0; i <= NMAX * AMAX; i++) {
    binom[i][0] = binom[i][i] = 1;
    for (j = 1; j < i; j++) {
      binom[i][j] = (binom[i-1][j] + binom[i-1][j-1]) % MOD;
    }
  }
  scanf("%d", &n);
  dp[0][0][0][0] = 1;
  for (i = 0; i < n; i++) {
    scanf("%d", &a);
    long long dupli = 1;
    for (j = 1; j <= a; j++) dupli *= j;
    for (j = 0; j <= s + 1; j++) {
      for (k = 0; k <= 7; k++) {
	for (l = 0; l <= 3; l++) {
	  for (x = 1; x <= MIN(s + 1, a); x++) {
	    if (dp[i][j][k][l]) {
	      m = 2 * (prea - l) - k;
	      for(J = 0; J <= MIN(x, j); J++) {
		for(K = 0; K <= MIN(x - J, k); K++) {
		  for(L = 0; L <= MIN(x - J - K, l); L++) {
		    for(M = 0; M <= MIN(x - J - K - L, m); M++) {
		      dp[i+1][j+k+l-J-K-L][K+2*L+M][a-x] = (dp[i+1][j+k+l-J-K-L][K+2*L+M][a-x] + dupli * binom[a-1][x-1] * binom[j][J] * binom[k][K] * binom[l][L] * binom[m][M] * binom[s-j-k-l-m+1][x-J-K-L-M] * dp[i][j][k][l]) % MOD;
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
    }
    s += a;
    prea = a;
  }
  printf("%d\n", dp[n][0][0][0]);
}