HDU 5816 Hearthstone

来源:互联网 发布:51单片机开发板哪个好 编辑:程序博客网 时间:2024/05/21 11:04

题目链接:
http://acm.split.hdu.edu.cn/showproblem.php?pid=5816

题目大意:
你在玩炉石,对手n滴血,你每次抽的卡有两种类型,一种类型是再抽两张,另一种类型是能打对手x点伤害,x会一一给出,问能一回合击败对手的可能性是多少。

解题思路:

这道题是3^n的算法。。。
i代表当前抽到牌的集合
dp[i]代表抽到这种牌有多少种抽法,枚举每一种情况,如果能打死对手,则答案数加上dp[i]*fact[t],fact[t]代表t的阶乘,t是还剩t张抽完,
再判断当前拥有的牌是否合法,比如不能只摸到两张伤害牌,如果合法,则向下转移,计算出下一种牌有多少种模法
if(!((i>>j)&1)) dp[i|(1<

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#include <string>#include <vector>#include <list>#include <map>#include <queue>#include <stack>#include <algorithm>#include <numeric>#include <functional>#define RI(N) scanf("%d",&(N))#define RII(N,M) scanf("%d %d",&(N),&(M))#define RIII(N,M,K) scanf("%d %d %d",&(N),&(M),&(K))#define mem(a) memset((a),0,sizeof(a))using namespace std;const int inf=1e9;const int inf1=-1*1e9;double EPS=1e-10;typedef long long LL;LL fact[25];LL dp[(1<<20)+5];int dam[25];LL tot;int p,n,m;void ini(){    fact[0]=1;    LL t=1;    for(int i=1; i<=20; i++)        {            t*=i;            fact[i]=t;        }}bool check(LL x){    int damm=0;    for(int i=0; i<m; i++)    {        if((x>>i)&1) damm+=dam[i];    }    if(damm>=p) return true;    return false;}LL cal(LL x){    LL num=0;    while(x)    {        num++;        x&=(x-1);    }    return num;}LL gcd(LL a,LL b){    if(b==0) return a;    return gcd(b,a%b);}int main(){    ini();    int T;    RI(T);    while(T--)    {        scanf("%d %d %d",&p,&n,&m);        for(int i=0; i<m; i++)            RI(dam[i]);        memset(dp,0,sizeof(dp));        LL tot=1<<(m+n);        LL ans=0;        for(int i=0; i<(n+m); i++) dp[1<<i]=1;        for(int i=0; i<tot; i++)        {            if(check(i))            {                int t=m+n-cal(i);                ans=ans+fact[t]*dp[i];                continue;            }            int aa=0,bb=0;            for(int j=m; j<m+n; j++)            {               if((i>>j)&1) aa++;            }            if(aa*2+1<=cal(i)) continue;            for(int j=0; j<m+n; j++)                if(!((i>>j)&1)) dp[i|(1<<j)]+=dp[i];        }        LL k=gcd(fact[n+m],ans);        printf("%I64d/%I64d\n",ans/k,fact[n+m]/k);    }    return 0;}
0 0
原创粉丝点击