BZOJ1079 [SCOI2008]着色方案 记忆化搜索

1079: [SCOI2008]着色方案

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2826  Solved: 1682
[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

一开始想的组合数学,但颜色数太多没法容斥。后来想到用dp,也想到用dp[a][b][c][d][e]维护数量为1,2,3,4,5,的颜色有a,b,c,d,e种的方案数,但是不太会递推啊...
题解:
看黄学长的题解用的记忆化搜索,用last记录上一层用掉的是数量为last的颜色,那么该层能用的last-1的颜色就少了一个,用f[a][b][c][d][e][last]维护数量为1,2,3,4,5,的颜色有a,b,c,d,e种的方案数。
当用掉一个数量为k的颜色时,增加的方案数为该层能用的数量为k的颜色数(即 num[k] -(last == k+1))*dfs(..,num[k-1]+1,num[k]-1,...,k)。
 
 1 /**************************************************************
 2     Problem: 1079
 3     User: mizersy
 4     Language: C++
 5     Result: Accepted
 6     Time:88 ms
 7     Memory:151292 kb
 8 ****************************************************************/
 9  
10 #include <bits/stdc++.h>
11 using namespace std;
12 typedef long long ll;
13 const ll mod = 1e9+7;
14 ll f[20][20][20][20][20][6];
15 ll k,w;
16 ll num[10];
17  
18 ll dfs(ll a,ll b,ll c,ll d,ll e,ll last){
19     if (f[a][b][c][d][e][last]) return f[a][b][c][d][e][last];
20     ll ret = 0;
21     if (a)
22         ret = (ret + (a - (last == 2)) * dfs(a-1,b,c,d,e,1) % mod) % mod;
23     if (b)
24         ret = (ret + (b - (last == 3)) * dfs(a+1,b-1,c,d,e,2) % mod) % mod;
25     if (c)
26         ret = (ret + (c - (last == 4)) * dfs(a,b+1,c-1,d,e,3) % mod) % mod;
27     if (d)
28         ret = (ret + (d - (last == 5)) * dfs(a,b,c+1,d-1,e,4) % mod) % mod;
29     if (e)
30         ret = (ret + e * dfs(a,b,c,d+1,e-1,5) % mod) % mod;
31     return f[a][b][c][d][e][last] = ret % mod;
32 }
33  
34  
35 int main(){
36     scanf("%lld",&k);
37     for (int i = 1;i <= k;++i){
38         scanf("%lld",&w);
39         num[w]++;
40     }
41     for (int i = 0;i <= 5;++i) f[0][0][0][0][0][i] = 1;
42     printf("%lld\n",dfs(num[1],num[2],num[3],num[4],num[5],0));
43 }

 

posted @ 2018-08-31 15:12  mizersy  阅读(176)  评论(0编辑  收藏  举报