zoukankan      html  css  js  c++  java
  • BZOJ1079: [SCOI2008]着色方案

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1079

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

    题解:dp,设f[a][b][c][d][e][last]表示可以使用一次的为a个,可以使用两次的为b个,以此类推到e,last表示前一个是可以用last次的。

       为什么要记录last??

       从dp方程可得:

       if (a+b+c+d+e==0) return f[a][b][c][d][e][kind]=1;
       if (f[a][b][c][d][e][kind]) return f[a][b][c][d][e][kind];
       if (a) (sum+=(a-(kind==2))*calc(a-1,b,c,d,e,1))%=mod;
       if (b) (sum+=(b-(kind==3))*calc(a+1,b-1,c,d,e,2))%=mod;
       if (c) (sum+=(c-(kind==4))*calc(a,b+1,c-1,d,e,3))%=mod;
       if (d) (sum+=(d-(kind==5))*calc(a,b,c+1,d-1,e,4))%=mod;
       if (e) (sum+=e*calc(a,b,c,d+1,e-1,5))%=mod;

       注释:kind即为last!

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #define ll long long 
    #define N 6
    #define mod 1000000007
    using namespace std;
    int k,sum[N],x;
    int f[16][16][16][16][16][6];
    ll ans; 
    int read()
    {
        int x=0; char ch; bool bo=0;
        while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1;
        while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9');
        if (bo) return -x; return x;
    }
    ll calc(int a,int b,int c,int d,int e,int kind)
    {
        ll sum=0;
        if (a+b+c+d+e==0) return f[a][b][c][d][e][kind]=1;
        if (f[a][b][c][d][e][kind]) return f[a][b][c][d][e][kind];
        if (a) (sum+=(a-(kind==2))*calc(a-1,b,c,d,e,1))%=mod;
        if (b) (sum+=(b-(kind==3))*calc(a+1,b-1,c,d,e,2))%=mod;
        if (c) (sum+=(c-(kind==4))*calc(a,b+1,c-1,d,e,3))%=mod;
        if (d) (sum+=(d-(kind==5))*calc(a,b,c+1,d-1,e,4))%=mod;
        if (e) (sum+=e*calc(a,b,c,d+1,e-1,5))%=mod;
        return f[a][b][c][d][e][kind]=sum%mod;
    }
    int main()
    {
        k=read();
        for (int i=1; i<=k; i++) x=read(),sum[x]++;
        ans=calc(sum[1],sum[2],sum[3],sum[4],sum[5],0);
        printf("%lld
    ",ans);
    }
    View Code
  • 相关阅读:
    Android中Chronometer 计时器和震动服务控件
    Android中几种常用的话框
    Android通过长按图片设置为壁纸
    Android把图片保存到SQLite中
    激活Win10
    SQL 语句解决实际问题
    在Foxmail邮件客户端登录263企业邮箱
    Visual Studio 安装VS10x CodeMAP
    开发常见问题汇总
    Java笔记:编写第一个Java程序
  • 原文地址:https://www.cnblogs.com/HQHQ/p/5620862.html
Copyright © 2011-2022 走看看