• HDU 4248【组合数学 + DP】 康某


    for my darling

    题意:有N种石头,每种石头有A1,A2....AN个,现取出一些石头组成序列,求可以组成多少种序列

    例如:3种:可以产生:B; G; M; BG; BM; GM; GB; MB; MG; BGM; BMG; GBM; GMB; MBG; MGB.

    我们采用动态规划的思想,划分阶段:按照石头种类划分阶段。于是乎,咱们对于第i种石头,相当于之前石头的颜色并不重要,借助高中数学插板法的思想,假如之前的i - 1 种石头,拼出了长度为len,那么,相当于有len + 1个空,咱们要放第 i 种石头进去,于是乎,转化成了经典问题,我比较得意的总结:

    球和球 盒和盒 空盒 情况数
    有区别 有区别 有空盒 m^n
    有区别 有区别 无空盒 M!s(n,m)
    有区别 无区别 有空盒 S(n,1)+s(n,2)+…+s(n,m),n>=m
          S(n,1)+s(n,2)+…+s(n,n),n<=m
    有区别 无区别 无空盒 S(n,m)
    无区别 有区别 有空盒 C(n+m-1,n)
    无区别 有区别 无空盒 C(n-1,m-1)
    无区别 无区别 有空盒 DP
    无区别 无区别 无空盒 DP

    这里,第 i 种石头互相没有区别,len + 1个空有序,相当于有区别,可以有空盒,于是,如果咱们从第 i 种中放put个进去,情况数应该是 C(put + len , put)

    于是设计状态:DP[i][j] 表示 用前 i 种石头,排出长度为 j 的可能数

    然后,状态转移的时候,枚举在阶段 i 放入put个,DP[i + 1][j + put] += DP[i][j] * C(put + j, put) 即可

    复杂度 10000 ^ 2,能过……

    写时候时间较紧,外加好久没刷HDU了……出现 1:忘记判EOF 2:长度为len,有len + 1个空,忘记 + 1了……于是一直没过……

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 typedef long long Long;
     5 
     6 const int MOD = 1000000007;
     7 
     8 int C[11111][111];
     9 
    10 void init() {
    11     C[0][0] = C[1][0] = C[1][1] = 1;
    12     for (int i = 2; i <= 10101; i++) {
    13         for (int j = 0; j <= i && j <= 100; j++) {
    14             if (j == 0) C[i][j] = 1;
    15             else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
    16         }
    17     }
    18 }
    19 
    20 
    21 int dp[111][11111];
    22 int a[111];
    23 
    24 int main() {
    25     init();
    26     for (int ii = 1;;ii++) {
    27         int n; if (scanf("%d",&n) == -1) break;
    28         memset(dp,0,sizeof(dp));
    29         memset(a,0,sizeof(a));
    30         for (int i = 0; i < n; i++) {
    31             scanf("%d",a + i);
    32         }
    33         for (int i = 0; i <= a[0]; i++) dp[0][i] = 1;
    34         int maxlen = a[0];
    35         for (int now = 0; now < n - 1; now ++) {
    36             int next = now + 1;
    37             for (int len = 0; len <= maxlen; len++) {
    38                 if (dp[now][len] == 0) continue;
    39                 dp[next][len] += dp[now][len];
    40                 if (dp[next][len] >= MOD) dp[next][len] -= MOD;
    41                 Long tmp = dp[now][len];
    42                 for (int put = 1; put <= a[next]; put++) {
    43                     Long tt = tmp * C[len + put][put] % MOD;
    44                     dp[next][len + put] += tt;
    45                     if (dp[next][len + put] >= MOD) dp[next][len + put] -= MOD;
    46                 }
    47             }
    48             maxlen += a[next];
    49         }
    50         int ans = 0;
    51         for (int i = 1; i <= maxlen; i++) ans = (ans + dp[n - 1][i]) % MOD;
    52         printf("Case %d: %d\n",ii,ans);
    53     }    
    54     return 0;
    55 }

     

  • 相关阅读:
    tslib編译和安装
    Web服务器的工作原理
    激励一生的六个经典故事
    VS2010中创建安装项目
    vue中img标签图片 加载时 与 加载失败 的处理方法
    Vue函数式组件的应用
    深入浅出Object.defineProperty()
    重学Git(一)
    backgroundblendmode
    箭头流程图前端实现
  • 原文地址:https://www.cnblogs.com/sweetsc/p/2595189.html
Copyright © 2020-2023  润新知