[SCOI2008]着色方案

附上题目网址:https://www.luogu.org/problemnew/show/P2476

想法:

看数据范围,发现Ci最高才能达到5所以可以进行搜索,又因为有些是一样的所以再存一个last表示上一个涂的颜色,实现记忆化

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 inline long long read()
 7 {
 8     long long f=1,ans=0;char c;
 9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
10     while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
11     return f*ans;
12 }
13 long long n,t[6],dp[16][16][16][16][16][6];//t是存能涂i下的数量,dp:注意到题目中的信息 1≤ci≤5 ,同时 相同的油漆本质上是相同的,于是我们令 f[c1][c2][c3][c4][c5][last] 表示当还能够涂 1 个格子的油漆有 c1 种,还能够涂 2 个格子的油漆有 c2 种……(以此类推)且按木块 1 ~ 那 编号顺序涂,上一次涂的是能够涂 last 个格子的油漆时的总方案数。
14 long long dfs(long long x1,long long x2,long long x3,long long x4,long long x5,long long last)//记忆化搜索
15 {
16     if(dp[x1][x2][x3][x4][x5][last]!=0) return dp[x1][x2][x3][x4][x5][last];//当搜到第二遍的时候,直接返回
17     if(x1+x2+x3+x4+x5==0) return 1;//当他们都没有的时候,没法再涂的时候,数量为1
18     long long ans=0;
19     if(x1!=0) ans+=(x1-(last==2))*dfs(x1-1,x2,x3,x4,x5,1);//回到我们所说的相邻情况,假设上一次用的是可以涂 last 个格子的油漆,那么上一次用完后,那种油漆就只可以涂 last−1 个格子了,那么这一次涂油漆的时候就不能再选可以涂 last−1 个格子的油漆的一种,因为这种上次已经用过了,且相同的油漆不能相邻。
20     if(x2!=0) ans+=(x2-(last==3))*dfs(x1+1,x2-1,x3,x4,x5,2);
21     if(x3!=0) ans+=(x3-(last==4))*dfs(x1,x2+1,x3-1,x4,x5,3);
22     if(x4!=0) ans+=(x4-(last==5))*dfs(x1,x2,x3+1,x4-1,x5,4);
23     if(x5!=0) ans+=x5*dfs(x1,x2,x3,x4+1,x5-1,5);
24     dp[x1][x2][x3][x4][x5][last]=ans%1000000007;//mod
25     return dp[x1][x2][x3][x4][x5][last];//返回数量
26 }
27 int main()
28 {
29     n=read();
30     for(long long i=1;i<=n;i++) 
31     {
32         long long x=read();
33         t[x]++;
34     }
35     cout<<dfs(t[1],t[2],t[3],t[4],t[5],0);
36 }
原文地址:https://www.cnblogs.com/si-rui-yang/p/9342794.html