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,终点已知,那么就不会有容斥关系。

  • 相关阅读:
    Python可视化库Matplotlib绘图基础学习
    字典特征和文本特征数据抽取
    ipc_11_快乐 happy
    关于Scanf的返回值问题
    [转]网站性能测试总结
    C语言运算符优先级
    成员运算符(·)和指向结构体成员运算符(->)的区别
    c++抛出异常与栈展开(stack unwinding)
    What is a Delegate?
    1.2 Variables and Arithmetic Expressions
  • 原文地址:https://www.cnblogs.com/dirge/p/5755177.html
Copyright © 2011-2022 走看看