hdu-5816 Hearthstone(状压dp+概率期望)

题目链接:

Hearthstone

Time Limit: 2000/1000 MS (Java/Others)  

  Memory Limit: 65536/65536 K (Java/Others)

Problem Description

Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation and your only hope depends on the top of the card deck, and you draw the only card to solve this dilemma. We call this "Shen Chou Gou" in Chinese.

Now you are asked to calculate the probability to become a "Shen Chou Gou" to kill your enemy in this turn. To simplify this problem, we assume that there are only two kinds of cards, and you don‘t need to consider the cost of the cards.
  -A-Card: If the card deck contains less than two cards, draw all the cards from the card deck; otherwise, draw two cards from the top of the card deck.
  -B-Card: Deal X damage to your enemy.

Note that different B-Cards may have different X values.
At the beginning, you have no cards in your hands. Your enemy has P Hit Points (HP). The card deck has N A-Cards and M B-Cards. The card deck has been shuffled randomly. At the beginning of your turn, you draw a card from the top of the card deck. You can use all the cards in your hands until you run out of it. Your task is to calculate the probability that you can win in this turn, i.e., can deal at least P damage to your enemy.

Input

The first line is the number of test cases T (T<=10). 
Then come three positive integers P (P<=1000), N and M (N+M<=20), representing the enemy’s HP, the number of A-Cards and the number of B-Cards in the card deck, respectively. Next line come M integers representing X (0<X<=1000) values for the B-Cards.

Output

For each test case, output the probability as a reduced fraction (i.e., the greatest common divisor of the numerator and denominator is 1). If the answer is zero (one), you should output 0/1 (1/1) instead.

Sample Input

2

3 1 2

1 2

3 5 10

1 1 1 1 1 1 1 1 1 1

Sample Output

1/3

46/273

题意:

给了n张A牌,m张B牌,A牌能取两张.B牌能打掉a[i]的血,问打掉至少p点血的概率是多少;

思路:

dp[i]表示i状态下的方案数,所求答案就是大于等于p点的状态的方案数总和与(n+m)!的比值;

状态的转移的话就是手中的A种牌在这个状态下是否还能拿牌,具体的可以看这个链接

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
//#include <bits/stdc++.h>
#include <stack>
#include <map>

using namespace std;

#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));

typedef  long long LL;

template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<‘0‘||CH>‘9‘;F= CH==‘-‘,CH=getchar());
    for(num=0;CH>=‘0‘&&CH<=‘9‘;num=num*10+CH-‘0‘,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + ‘0‘);
    putchar(‘\n‘);
}

const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=1e5+10;
const int maxn=(1<<20)+14;
const double eps=1e-12;

LL dp[maxn],f[23];
int num[maxn],p,n,m,a[30];
inline void Init()
{
    for(int i=0;i<maxn;i++)
    {
        for(int j=0;j<20;j++)
        {
            if(i&(1<<j))num[i]++;
        }
    }
    f[0]=1;
    for(int i=1;i<=20;i++)f[i]=f[i-1]*i;
}
int cal(int x)
{
    int sum=0;
    for(int i=0;i<m;i++)
    {
        if(x&(1<<i))sum+=a[i];
    }
    return sum;
}

LL gcd(LL x,LL y)
{
    if(y==0)return x;
    return gcd(y,x%y);
}
int counter(int x)
{
    int sum=0;
    for(int i=0;i<m;i++)
    {
        if(x&(1<<i))sum++;
    }
    return num[x]-2*sum+1;
}
int main()
{
    Init();
    int t;
    read(t);
    while(t--)
    {
        mst(dp,0);
        read(p);read(n);read(m);
        For(i,0,m-1)read(a[i]);
        LL ans=0;
        int tot=(1<<(n+m))-1;
        dp[0]=1;
        for(int i=0;i<=tot;i++)
        {
            if(!dp[i])continue;
            if(i==tot||counter(i)==0)
            {
                if(cal(i)>=p)ans=ans+dp[i]*f[n+m-num[i]];
            }
            else
            {
                for(int j=0;j<n+m;j++)
                {
                    if(i&(1<<j))continue;
                    dp[i|(1<<j)]+=dp[i];
                }
            }
        }
        LL g=gcd(ans,f[n+m]);
        cout<<ans/g<<"/"<<f[n+m]/g<<"\n";
    }
    return 0;
}

  

时间: 2024-10-08 21:14:07

hdu-5816 Hearthstone(状压dp+概率期望)的相关文章

多校7 HDU5816 Hearthstone 状压DP+全排列

1 多校7 HDU5816 Hearthstone 状压DP+全排列 2 题意:boss的PH为p,n张A牌,m张B牌.抽取一张牌,能胜利的概率是多少? 3 如果抽到的是A牌,当剩余牌的数目不少于2张,再从剩余牌里抽两张,否则全部拿完. 4 每次拿到一张B牌,对boss伤害B[i]的值 5 思路:dp[i]表示状态为i时的方案数 6 先处理出所有状态下的方案,再枚举每种状态,如果符合ans+=dp[i]*剩余数的全排列 7 当前集合里有a张A,b张B,那么还能取的牌数:a*2-a-b+1 8 9

HDU 4284Travel(状压DP)

HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1 由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

HDU 3681 BFS&amp;状压DP&amp;二分

N*M矩阵,从F点出发,走完所有的Y点,每走一格花费1点电量,走到G点时,电量充满,D不可到达,问起始时的最小满电量可以走完所有Y,Y和G一共最多15个 先BFS出所有的F,Y,G之间的最短距离. 然后二分起始电量,对每个电量,做状压DP判断是否可行 #include "stdio.h" #include "string.h" #include "queue" using namespace std; int inf=0x3f3f3f3f; in

LianLianKan HDU - 4272(状压dp)

题意:就是连连看,有两个相同的就能消除,再加上两个特别的规定,一是只能从栈顶开始消除,而是两个相同的元素之间距离不能超过6,询问能否消除序列中所有元素. 思路:数据水,贪心就能过,但严谨的考虑,贪心显然不能解决所有问题.这题虽然序列很长,但是状态并不复杂,可以使用滚动的状压dp,然后考虑使用多少位表示状态,每一种状态表示第i位为栈首的序列状态,该位前最多能消除掉该位后四位,所以我们只需要表示后9位的状态即可,总计10位. 某位上1表示该位已被消除,0表示未被消除. dp[i][j]表示从i位开始

方格取数(1) HDU - 1565 (状压dp)

给你一个n*n的格子的棋盘,每个格子里面有一个非负数.     从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188 思路:状压dp,建立dp[i][j]二维数组,表示第i行状

hdu 2825 (Aho-Corasick &amp; 状压DP) - xgtao -

题目链接 给出m(m<=10)个模板串,问长度为n(n<=25)的字符串包含至少k个模板串的种类数,对20090717取模. 套路,有多个模板串考虑Aho-Corasick,因为想了很久找不到什么可行办法做,就考虑Dp,因为m<=10,所以可以有状压来检查当前状态下已经包含多少个模板串了,因为在一棵trie树上,那么定义状态也好定义,dp[len][id][s]表示长度为len时处在第id个节点并且状态为s,转移方程为dp[len+1][nextid][s|nexts] += dp[le

HDU Untitled(状压DP OR dfs枚举子集)

Untitled Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 325    Accepted Submission(s): 169 Problem Description There is an integer a and n integers b1,-,bn. After selecting some numbers from b