看到这种方案数特别多的题目就想推公式。。。
最朴素的可以想出15维的方程来递推,但其实C值不同的木板只有5种,而它们的本质都是相同的。
这样我们可以设计一个6维的方程f[a][b][c][d][e][last]表示C值为1 ~5的油漆颜色总数,last表示上次选的油漆的C值
方程的话就很直观了,使用记忆话搜索实现。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 16;
const int maxm = 6;
const int mo = 1000000007;
long long f[maxn][maxn][maxn][maxn][maxn][maxm];
bool vis[maxn][maxn][maxn][maxn][maxn][maxm];
int k;
int s[maxn];
void init()
{
freopen("bzoj1079.in","r",stdin);
freopen("bzoj1079.out","w",stdout);
}
void readdata()
{
int t;
scanf("%d",&k);
for(int i = 1;i <= k;i++)
{
scanf("%d",&t);
s[t]++;
}
}
long long dfs(int a,int b,int c,int d,int e,int x)
{
if(a + b + c + d + e == 0)return 1;
long long tmp = 0;
if(vis[a][b][c][d][e][x])return f[a][b][c][d][e][x];
vis[a][b][c][d][e][x] = true;
if(a)tmp += (a - (x == 2)) * dfs(a-1,b,c,d,e,1);
if(b)tmp += (b - (x == 3)) * dfs(a+1,b-1,c,d,e,2);
if(c)tmp += (c - (x == 4)) * dfs(a,b+1,c-1,d,e,3);
if(d)tmp += (d - (x == 5)) * dfs(a,b,c+1,d-1,e,4);
if(e)tmp += e * dfs(a,b,c,d+1,e-1,5);
tmp %= mo;
f[a][b][c][d][e][x] = tmp;
return f[a][b][c][d][e][x];
}
void solve()
{
printf("%lld\n",dfs(s[1],s[2],s[3],s[4],s[5],0));
}
int main()
{
init();
readdata();
solve();
return 0;
}