来源:牛客网:
@[toc]

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

有n个木块排成一行,从左到右依次编号为1~n。 你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。
所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n。
相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。

输入描述:

第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。

输出描述:

输出一个整数,即方案总数模1,000,000,007的结果。

示例1
输入
复制

3
1 2 3

输出
复制

10

1<=k<=15 ,1<= ci <=5

题解:

记忆化搜索
dp[a][b][c][d][e][last]
表示每一种颜色分别剩下啊a,b,c,d,e个方案数,有a种一个(可以涂1块木块的有多少种颜***种两个,c种三个....e种五个,last表示上一次用的是可以涂last个木块的油漆
因为我们不能连续涂两块相同的颜色,如果上一次用的还能涂i次的油漆,那么当前就多一种还能涂i-1次的油漆未使用
所以如果b-1的话,a要+1,一次类推都是这样
然后考虑转移方程:

dp[a][b][c][d][e][1]=dp[a-1][b][c][d][e][1]*a+dp[a+1][b-1][c][d][e][2]*b+dp[a][b+1][c-1][d][e][3]*c+dp[a][b][c+1][d-1][e][4]*d+dp[a][b][c][d+1][e-1][5]*e 

我们在递推中可以写成这种形式

if(a1) ans = (ans + 1ll * (a1 - (last == 2)) * dfs(a1 - 1, a2, a3, a4, a5, 1)) % mod;

(last==2)则是特判上一种颜色的种类,否则会造成重复

代码:

#include <bits/stdc++.h>

const int mod = 1e9 + 7;
using namespace std;

typedef long long ll;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')    f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (c ^ 48);
    c = getchar();
  }
  return f * x;
}

void print(ll x) {
  if(x < 10) {
    putchar(x + 48);
    return ;
  }
  print(x / 10);
  putchar(x % 10 + 48);
}



ll dp[20][20][20][20][20][10];
int n, a[10];

ll dfs(int a1, int a2, int a3, int a4, int a5, int last) {
  if(dp[a1][a2][a3][a4][a5][last]) return dp[a1][a2][a3][a4][a5][last];
  ll ans = 0;
  if(a1) ans = (ans + 1ll * (a1 - (last == 2)) * dfs(a1 - 1, a2, a3, a4, a5, 1)) % mod;
  if(a2) ans = (ans + 1ll * (a2 - (last == 3)) * dfs(a1 + 1, a2 - 1, a3, a4, a5, 2)) % mod;
  if(a3) ans = (ans + 1ll * (a3 - (last == 4)) * dfs(a1, a2 + 1, a3 - 1, a4, a5, 3)) % mod;
  if(a4) ans = (ans + 1ll * (a4 - (last == 5)) * dfs(a1, a2, a3 + 1, a4 - 1, a5, 4)) % mod;
  if(a5) ans = (ans + 1ll * a5 * dfs(a1, a2, a3, a4 + 1, a5 - 1, 5)) % mod;
  return dp[a1][a2][a3][a4][a5][last] = ans;
}

int main() {
  n = read();
  for(int i = 1; i <= n; i++) {
    int x = read();
    a[x]++;
  }
  for(int i = 1; i <= 5; i++) dp[0][0][0][0][0][i] = 1;
  print(dfs(a[1], a[2], a[3], a[4], a[5], 0));
    return 0;
}