dp...或者说是记忆化搜索吧....
注意到 1 <= c_i <= 5 , 虽然 1 <= k <= 15 , 但是我们可以把剩下油漆数相同的看做等价类
dp( a , b , c , d , e , p ) 表示剩下油漆数为 1 的油漆有 a 种 , 剩下油漆数为 2 的油漆有 b 种 …… p 表示上一个木块是用了哪一种油漆着色 . 然后转移就看 code 吧...
--------------------------------------------------------------------
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define mod( x ) ( ( x ) %= MOD )
using namespace std;
const int MOD = 1e9 + 7;
const int maxn = 17;
int h[ maxn ][ maxn ][ maxn ][ maxn ][ maxn ][ maxn ];
int dfs( int a , int b , int c , int d , int e , int p ) {
int &ans = h[ a ][ b ][ c ][ d ][ e ][ p ];
if( ans ) return ans;
ans = 0;
if( a ) mod( ans += 1LL * ( a - ( p == 2 ) ) * dfs( a - 1 , b , c , d , e , 1 ) % MOD );
if( b ) mod( ans += 1LL * ( b - ( p == 3 ) ) * dfs( a + 1 , b - 1 , c , d , e , 2 ) % MOD );
if( c ) mod( ans += 1LL * ( c - ( p == 4 ) ) * dfs( a , b + 1 , c - 1 , d , e , 3 ) % MOD );
if( d ) mod( ans += 1LL * ( d - ( p == 5 ) ) * dfs( a , b , c + 1 , d - 1 , e , 4 ) % MOD );
if( e ) mod( ans += 1LL * e * dfs( a , b , c , d + 1 , e - 1 , 5 ) % MOD );
return ans;
}
int main() {
freopen( "test.in" , "r" , stdin );
clr( h , 0 );
rep( i , 6 ) h[ 0 ][ 0 ][ 0 ][ 0 ][ 0 ][ i ] = 1;
int k , t[ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 };
cin >> k;
while( k-- ) {
int v;
scanf( "%d" , &v );
t[ v ]++;
}
cout << dfs( t[ 1 ] , t[ 2 ] , t[ 3 ] , t[ 4 ] , t[ 5 ] , 0 ) << "\n";
return 0;
}
--------------------------------------------------------------------
1079: [SCOI2008]着色方案
Time Limit: 10 Sec
Memory Limit: 162 MB
Submit: 1100
Solved: 697
[
Submit][
Status][
Discuss]
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
Source