# 题意

$n$个木块排成一行，从左到右依次编号为$1$~$n$。你有$k$种颜色的油漆，其中第$i$种颜色的油漆足够涂$c_i$个木块。所有油漆刚好足够涂满所有木块，即$\sum\limits _{i=1}^{k}c_i=n$。统计任意两个相邻木块颜色不同的着色方案。($1 \le k \le 15$ ,$1\le c_i \le 5$)

# 题解

dp[a][b][c][d][e] = dp[a - 1][b][c][d][e] * a + dp[a + 1][b - 1][c][d][e] * b + dp[a][b + 1][c - 1][d][e] * c + dp[a][b][c + 1][d - 1][e] * d + dp[a][b][c][d + 1][e - 1] * e; （之间的+1,-1就是前面一种颜料从能涂q块，变成q-1了）

# 代码

/**************************************************************
Problem: 1079
Language: C++
Result: Accepted
Time:752 ms
Memory:67848 kb
****************************************************************/

#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;

bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}

int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
return x * fh;
}

void File () {
freopen ("P1079.in", "r", stdin);
freopen ("P1079.out", "w", stdout);
#endif
}

const int N = 17, Mod = 1e9 + 7;
typedef long long ll;

ll dp[N][N][N][N][N][6];

ll Dp(int a, int b, int c, int d, int e, int last) {
if ((a | b | c | d | e) == 0) return 1;
ll &res = dp[a][b][c][d][e][last];
if (~res) return res; res = 0;
if (a) res += Dp(a - 1, b, c, d, e, 1) * (a - (last == 2) );
if (b) res += Dp(a + 1, b - 1, c, d, e, 2) * (b - (last == 3) );
if (c) res += Dp(a, b + 1, c - 1, d, e, 3) * (c - (last == 4) );
if (d) res += Dp(a, b, c + 1, d - 1, e, 4) * (d - (last == 5) );
if (e) res += Dp(a, b, c, d + 1, e - 1, 5) * e;
res %= Mod;
return res;
}

int main () {
File();
int n = read(), a[6] = {0};
For (i, 1, n) ++ a[read()];
Set(dp, -1);
printf ("%lld\n", Dp(a[1], a[2], a[3], a[4], a[5], 0) );
return 0;
}

posted @ 2018-02-09 19:58  zjp_shadow  阅读(213)  评论(2编辑  收藏