记忆化搜索 [SCOI2008]着色方案
问题 B: [SCOI2008]着色方案
时间限制: 1 Sec 内存限制: 162 MB
提交: 80 解决: 38
[提交][状态][讨论版]
题目描述
有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。
所有油漆刚好足够涂满所有木块,即c1+c2+…+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两
个相邻木块颜色不同的着色方案。
输入
第一行为一个正整数k,第二行包含k个整数c1, c2, … , ck。
输出
输出一个整数,即方案总数模1,000,000,007的结果。
样例输入
3
1 2 3
样例输出
10
我们可以发现,可用剩余次数相同的颜色并没必要区别它们,直接记录还有多少种就行了。因此,我们每使用一种颜色,此剩余使用数量的颜色减一,使用数量减一的颜色种数加一。那么方案数+=此次数颜色数量×修改之后的方案总数。但考虑颜色不能连续,搜的时候判断就行了,如果是同一种剩余次数的颜色,-1就行了。
而且颜色很少?使用次数最大为5?可以开个6维数组记录各剩下多少和上一个是什么就行了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#define mod 1000000007
#define ll long long
using namespace std;
int k,a[6];ll f[16][16][16][16][16][6];
ll dfs(int a1,int a2,int a3,int a4,int a5,int las)
{
if((a1|a2|a3|a4|a5)==0)return f[a1][a2][a3][a4][a5][las]=1;
if(f[a1][a2][a3][a4][a5][las])return f[a1][a2][a3][a4][a5][las];
ll s=0;
if(a1)s+=(a1-(las==2))*dfs(a1-1,a2,a3,a4,a5,1),s%=mod;
if(a2)s+=(a2-(las==3))*dfs(a1+1,a2-1,a3,a4,a5,2),s%=mod;
if(a3)s+=(a3-(las==4))*dfs(a1,a2+1,a3-1,a4,a5,3),s%=mod;
if(a4)s+=(a4-(las==5))*dfs(a1,a2,a3+1,a4-1,a5,4),s%=mod;
if(a5)s+=a5*dfs(a1,a2,a3,a4+1,a5-1,5),s%=mod;
return f[a1][a2][a3][a4][a5][las]=s;
}
int main()
{
scanf("%d",&k);int x;
for(int i=1;i<=k;i++)scanf("%d",&x),a[x]++;
printf("%lld\n",dfs(a[1],a[2],a[3],a[4],a[5],0));
}