[SCOI2008]着色方案 bzoj1079/洛谷2476

题目描述
有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其

中第i 种颜色的油漆足够涂ci 个木块。所有油漆刚好足够涂满所有木块,即

c1+c2+…+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相

邻木块颜色不同的着色方案。

输入输出格式
输入格式:
第一行为一个正整数k,第二行包含k个整数c1, c2, … , ck。

输出格式:
输出一个整数,即方案总数模1,000,000,007的结果。

题解

f[c1][c2][c3][c4][c5][last] f [ c 1 ] [ c 2 ] [ c 3 ] [ c 4 ] [ c 5 ] [ l a s t ] 表示上一个木块涂的颜色可以涂last块(包括上一块),能涂i块木块的颜色有ci种的最优解。

f[c1][c2][c3][c4][c5][last]+= f [ c 1 ] [ c 2 ] [ c 3 ] [ c 4 ] [ c 5 ] [ l a s t ] + =
(c1(last==2))f[c11][c2][c3][c4][c5][1] ( c 1 − ( l a s t == 2 ) ) ∗ f [ c 1 − 1 ] [ c 2 ] [ c 3 ] [ c 4 ] [ c 5 ] [ 1 ]
(c2(last==3))f[c1+1][c21][c3][c4][c5][2] ( c 2 − ( l a s t == 3 ) ) ∗ f [ c 1 + 1 ] [ c 2 − 1 ] [ c 3 ] [ c 4 ] [ c 5 ] [ 2 ]
(c3(last==4))f[c1][c2+1][c31][c4][c5][3] ( c 3 − ( l a s t == 4 ) ) ∗ f [ c 1 ] [ c 2 + 1 ] [ c 3 − 1 ] [ c 4 ] [ c 5 ] [ 3 ]
(c4(last==5))f[c1][[c2][c3+1][c41][c5][4] ( c 4 − ( l a s t == 5 ) ) ∗ f [ c 1 ] [ [ c 2 ] [ c 3 + 1 ] [ c 4 − 1 ] [ c 5 ] [ 4 ]
c5f[c1][c2][c3][c4+1][c5][5] c 5 ∗ f [ c 1 ] [ c 2 ] [ c 3 ] [ c 4 + 1 ] [ c 5 ] [ 5 ]

#include<cstdio>
#include<string>
using namespace std;
const int MOD=1e9+7;
long long K,num[6],f[16][16][16][16][16][6];
inline int read() {
    int ret=0,f=1;char ch=getchar();
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
    for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
    return ret*f;
}
long long dfs(int c1,int c2,int c3,int c4,int c5,int last) {
    if (f[c1][c2][c3][c4][c5][last]) return f[c1][c2][c3][c4][c5][last];
    long long res=0;
    if (c1) (res+=(c1-(last==2))*dfs(c1-1,c2,c3,c4,c5,1))%=MOD;
    if (c2) (res+=(c2-(last==3))*dfs(c1+1,c2-1,c3,c4,c5,2))%=MOD;
    if (c3) (res+=(c3-(last==4))*dfs(c1,c2+1,c3-1,c4,c5,3))%=MOD;
    if (c4) (res+=(c4-(last==5))*dfs(c1,c2,c3+1,c4-1,c5,4))%=MOD;
    if (c5) (res+=c5*dfs(c1,c2,c3,c4+1,c5-1,5))%=MOD;
    return f[c1][c2][c3][c4][c5][last]=res;
}
int main() {
    K=read();
    for (int i=1; i<=K; i++) num[read()]++;
    for (int i=1; i<=5; i++) f[0][0][0][0][0][i]=1;
    printf("%lld\n",dfs(num[1],num[2],num[3],num[4],num[5],0));
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值