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

    Description

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

    Input

      第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。

    Output

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

    Sample Input

    3
    1 2 3

    Sample Output

    10

    HINT

     100%的数据满足:1 <= k <= 15, 1 <= ci <= 5

     

     

    正解:记忆化搜索(DP)

    解题报告:

      这道题好神啊,合并操作的确很具有代表性。

      如果考虑如何求方案数,不妨DP统计,因为直接枚举与转移复杂度太大。我们选择把剩余可涂次数相等的分为一类,考虑因为只要剩余可涂次数相等,那么其实这些颜色并没有什么区别,因为我们涂颜色的时候只需要考虑涂的这种颜色剩余次数即可,并不需要考虑具体是什么颜色(先不考虑相邻颜色不能相等的限制)。

      那么令f[a1][a2][a3][a4][a5]表示剩余可涂一次的颜色种类数为a1,涂二次颜色种类数为a2...这样的情况的方案数。

      显然如果我们当前这次选的是剩余次数为x次的颜色,那么剩余次数为x次的颜色有多少种,就有多少种情况可以转移过来,只需要乘以数量就可以了。

      但是我们还没考虑相邻不能相等的情况,那么我们必须要少算一次,比如说如果上次填的是颜色剩余次数为2的,意味着颜色中剩余次数为1的多了一个,那么这一次并不能再选这种颜色,这次可以选填1的就要少1。

     

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MOD = 1000000007;
    21 int n,num[10001];
    22 LL f[16][16][16][16][16][6];//按每种颜色的剩余次数分类,剩余次数相同的分在一类
    23 
    24 inline int getint()
    25 {
    26        int w=0,q=0;
    27        char c=getchar();
    28        while((c<'0' || c>'9') && c!='-') c=getchar();
    29        if (c=='-')  q=1, c=getchar();
    30        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    31        return q ? -w : w;
    32 }
    33 
    34 inline LL dp(int a1,int a2,int a3,int a4,int a5,int last){    
    35     if( (a1 | a2 | a3 | a4 | a5 ) == 0)  return f[a1][a2][a3][a4][a5][last]=1;
    36     if(f[a1][a2][a3][a4][a5][last]) return f[a1][a2][a3][a4][a5][last];
    37     LL now=0;
    38     //考虑枚举这次选哪种剩余次数的颜色,一共有多少个剩余这种次数的个数就有多少种选择
    39     if(a1) now+=(a1-(last==2))*dp(a1-1,a2,a3,a4,a5,1),now%=MOD;//如果上次填的是颜色剩余次数为2的,意味着颜色中剩余次数为1的多了一个,那么这一次并不能再选这种颜色,这次可以选填1的就要少1。
    40     if(a2) now+=(a2-(last==3))*dp(a1+1,a2-1,a3,a4,a5,2),now%=MOD;
    41     if(a3) now+=(a3-(last==4))*dp(a1,a2+1,a3-1,a4,a5,3),now%=MOD;
    42     if(a4) now+=(a4-(last==5))*dp(a1,a2,a3+1,a4-1,a5,4),now%=MOD;
    43     if(a5) now+=a5*dp(a1,a2,a3,a4+1,a5-1,5),now%=MOD;//显然不需要考虑6的情况
    44     f[a1][a2][a3][a4][a5][last]=now;
    45     return now;
    46 }
    47 
    48 inline void work(){
    49     n=getint(); int x; for(int i=1;i<=n;i++) x=getint(),num[x]++;
    50     printf("%lld",dp(num[1],num[2],num[3],num[4],num[5],0));
    51 }
    52 
    53 int main()
    54 {
    55   work();
    56   return 0;
    57 }
  • 相关阅读:
    ASP.NET Core 问题排查:Request.EnableRewind 后第一次读取不到 Request.Body
    解决 AutoMapper ProjectTo 不起作用的问题
    解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题
    ASP.NET Core 从 gitlab-ci 环境变量读取配置
    终于解决 xUnit.net 测试中无法输出到控制台的问题
    ASP.NET Core 新建线程中使用依赖注入的问题
    前端回顾:2016年 JavaScript 之星
    前端工程师和设计师必读文章推荐【系列三十五】
    AsciiMorph
    Notyf
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5771185.html
Copyright © 2011-2022 走看看