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

来源:互联网 发布:淘宝大学原道电商学院 编辑:程序博客网 时间:2024/06/04 23:19

问题 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 longusing 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));}
原创粉丝点击