大家都很强, 可与之共勉 。
不看题解不会,看了秒题系列
着色方案
Description
有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。
所有油漆刚好足够涂满所有木块,即c1+c2+…+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两
个相邻木块颜色不同的着色方案。
Input
第一行为一个正整数k,第二行包含k个整数c1, c2, … , ck。
Output
输出一个整数,即方案总数模1,000,000,007的结果。
Sample Input
3
1 2 3
Sample Output
10
HINT
100%的数据满足:1 <= k <= 15, 1 <= ci <= 5
f[a][b][c][d][e][x]表示能涂一个格子的油漆有a种,能涂两个格子的油漆有b种…x表示的是上一次涂的是能涂x个格子的油漆;
f[a][b][c][d][e][x]=f[a-1][b][c][d][e](a-(x==2))+f[a+1][b-1][c][d][e](b-(x==3))+…+f[a][b][c][d+1][e-1]*(a-(x==6));
这个方程表示,剩下a,b,c,d,e,上次的是x,
假设这次要用可以涂k个格子的油漆,那么涂完这个格子,可以涂k个格子的油漆少了一种,可以涂k-1个格子的油漆多了一种;
这就是为什么b-1的时候a+1,c-1的时候b+1的原因;
还有就是相邻的格子的颜色不同,假设上一次用的是可以涂x个格子的油漆,那么上一次用完后的那种油漆就变成了一种可以涂x-1个格子的油漆了,那么这一次再选油漆的时候就不能再选可以涂x-1个格子的油漆的一种(这种上次一就用过了);所以对应的是(a-(x==2))和(b-(x==3))这些了。
# include <cstdio>
const int Mod = 1000000007 ;
int n, cnt [6] ;
long long dp [16] [16] [16] [16] [16] [6] ;
inline long long DP ( int a1, int a2, int a3, int a4, int a5, int last ) {
if( ( a1 | a2 | a3 | a4 | a5 ) == 0 ) return dp [a1] [a2] [a3] [a4] [a5] [last] = 1 ;
if ( dp [a1] [a2] [a3] [a4] [a5] [last] ) return dp [a1] [a2] [a3] [a4] [a5] [last] ;
long long now ( 0 ) ;
if ( a1 ) now += ( a1 - ( last == 2 ) ) * DP ( a1 - 1, a2, a3, a4, a5, 1 ), now %= Mod ;
if ( a2 ) now += ( a2 - ( last == 3 ) ) * DP ( a1 + 1, a2 - 1, a3, a4, a5, 2 ), now %= Mod ;
if ( a3 ) now += ( a3 - ( last == 4 ) ) * DP ( a1, a2 + 1, a3 - 1, a4, a5, 3 ), now %= Mod ;
if ( a4 ) now += ( a4 - ( last == 5 ) ) * DP ( a1, a2, a3 + 1, a4 - 1, a5, 4 ), now %= Mod ;
if ( a5 ) now += a5 * DP ( a1, a2, a3, a4 + 1, a5 - 1, 5 ) , now %= Mod ;
return dp [a1] [a2] [a3] [a4] [a5] [last] = now ;
}
int main ( ) {
scanf ( "%d", & n ) ;
for ( int i = 0, x ; i < n ; ++ i ) scanf ( "%d", & x ), ++ cnt [x] ;
return printf ( "%lld\n", DP ( cnt [1], cnt [2], cnt [3], cnt [4], cnt [5], 0 ) ), 0 ;
}