BZOJ1079 [SCOI2008]着色方案 动态规划

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1079


题目概括

  有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。


 

题解

  一开始想状压dp,压每种颜色的剩余数。

  发现要超时。

  访问了hzwer大佬的博客,立刻恍然大悟。

  我们可以压每种剩余数的颜色个数!

  具体:

  dp[a][b][c][d][e][t]表示剩余1的颜色有a个,剩余2的颜色有b个,剩余3的颜色有c个,剩余4的颜色有d个,剩余5的颜色有e个,之前选择的那种颜色现在还剩t的方案总数。

  那么复杂度为165×6≈6500000,应该不会超时了。

  记忆化dfs比较好写,所以写了记忆化dfs。


 

代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const LL mod=1000000007;
int k,tot[6];
LL dp[16][16][16][16][16][6];
LL DP(int a,int b,int c,int d,int e,int t){
    if (dp[a][b][c][d][e][t]!=-1)
        return dp[a][b][c][d][e][t];
    if (a+b+c+d+e==0)
        return dp[a][b][c][d][e][t]=1;
    int A=a-(t==1),B=b-(t==2),C=c-(t==3),D=d-(t==4),E=e;
    LL &res=dp[a][b][c][d][e][t];
    res=0;
    if (a)
        res+=A*DP(a-1,b,c,d,e,0);
    if (b)
        res+=B*DP(a+1,b-1,c,d,e,1);
    if (c)
        res+=C*DP(a,b+1,c-1,d,e,2);
    if (d)
        res+=D*DP(a,b,c+1,d-1,e,3);
    if (e)
        res+=E*DP(a,b,c,d+1,e-1,4);
    return res%=mod;
}
int main(){
    memset(dp,-1,sizeof dp);
    memset(tot,0,sizeof tot);
    scanf("%d",&k);
    for (int i=1,a;i<=k;i++){
        scanf("%d",&a);
        tot[a]++;
    }
    printf("%lld",DP(tot[1],tot[2],tot[3],tot[4],tot[5],0));
    return 0;
}

 

转载于:https://www.cnblogs.com/zhouzhendong/p/BZOJ1079.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值