zoukankan      html  css  js  c++  java
  • hdu5816 卡特兰数+dp

    题意:共n张无中生有,m张攻击牌。每张攻击牌攻击力已知,敌方有p点血。随机洗牌。游戏开始,己方抽取一张手牌,若是无中生有则可再抽两张牌。求能在第一回合内将敌方杀死的概率。

    n+m <= 20, p <= 1000;

    很明显,与卡特兰数有关,原先栈内数量为1,抽到无中生有即入栈,否则出栈。

    枚举攻击牌,求出该攻击牌组合下,用完所有手牌将对方杀死的方案数,以及抽光所有牌将对方杀死的方案数(手牌有剩)。

    不算预处理的复杂度,每组数据的时间复杂度为O(2^m)

     1 #include <cstdio>
     2 typedef long long ll;
     3 
     4 int bc[1<<20], sum[1<<20], tmp[1<<20];
     5 int C[21][21];
     6 ll fact[21];
     7 
     8 ll gcd(ll a, ll b){
     9     return b == 0? a :gcd(b, a%b);
    10 }
    11 
    12 void init(){
    13     int i, j;
    14     bc[0] = 0;
    15     for (i=1; i<(1<<20); i++) bc[i] = bc[i^(i&-i)] + 1;
    16     fact[0] = 1;
    17     for (i=1; i<=20; i++) fact[i] = fact[i-1] * i;
    18     C[0][0] = 1;
    19     for (i=1; i<=20; i++){
    20         C[i][0] = C[i][i] = 1;
    21         for (j=1; j<i; j++) C[i][j] = C[i-1][j] + C[i-1][j-1];
    22     }
    23 }
    24 
    25 int main(){
    26     ll a, b, d;
    27     int p, n, m, t, i;
    28     init();
    29     scanf("%d", &t);
    30     while (t --){
    31         scanf("%d %d %d", &p, &n, &m);
    32         for (i=0; i<m; i++) scanf("%d", &tmp[1<<i]);
    33         sum[0] = 0;
    34         for (i=1; i<(1<<m); i++) sum[i] = sum[i^(i&-i)] + tmp[i&-i];
    35         a = 0;
    36         for (i=0; i<(1<<m); i++){
    37             if (sum[i] >= p && bc[i] <= n + 1){
    38                 //C(n + m − 1,m) − C(n + m − 1,m − 1)
    39                 //手牌用完,到(bc[i], bc[i])的方案数,即到(bc[i], bc[i]-1)的方案数, 需要bc[i]-1张无中生有
    40                 a += C[n][bc[i]-1] * (C[ bc[i]+bc[i]-2 ][ bc[i]-1 ] - C[ bc[i]+bc[i]-2 ][ bc[i]-2 ])* fact[bc[i]-1] * fact[bc[i]] * fact[n+m-2*bc[i]+1];
    41                 //手牌用不完, 到(n+1, m)的方案数
    42                 if(bc[i] == m&&bc[i] < n+1)
    43                     a += (C[ m+n ][ m ] - C[ m+n ][ m-1 ])* fact[n] * fact[m];
    44             }
    45         }
    46         b = fact[n+m];
    47         d = gcd(a, b);
    48         printf("%I64d/%I64d
    ", a / d, b / d);
    49     }
    50     return 0;
    51 }
    View Code

     当时写的时候是以 状态表示的牌将敌方杀死 作为结束点,似乎还要容斥,比如用1,2,3杀死对方和用1,2就杀死对方,复杂度也可能会爆炸;

    其实应该换一个角度,考虑手牌用光将对方杀死,再加上手牌用不光的case,终点已知,那么就不会有容斥关系。

  • 相关阅读:
    poj 3321 Apple Tree
    hdu 1520 Anniversary party
    Light OJ 1089 Points in Segments (II)
    Timus 1018 Binary Apple Tree
    zoj 3299 Fall the Brick
    HFUT 1287 法默尔的农场
    Codeforces 159C String Manipulation 1.0
    GraphQL + React Apollo + React Hook 大型项目实战(32 个视频)
    使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
    GraphQL + React Apollo + React Hook + Express + Mongodb 大型前后端分离项目实战之后端(19 个视频)
  • 原文地址:https://www.cnblogs.com/dirge/p/5755177.html
Copyright © 2011-2022 走看看