HDU 5816 Hearthstone(状压DP)
2016-08-30 19:36
309 查看
Description
有一个卡组,有两种卡牌,A牌n张,B牌m张,抽到一张A牌可以从卡组中再抽两张,抽到一张B牌可以给敌人造成一定的伤害,现在告诉敌人的血量P以及m张B牌的伤害值,初始状态可以从卡组中拿一张牌,问有多大概率可以打败敌人(即抽到牌的总伤害值大于等于敌人的血量)
Input
第一行一整数T表示用例组数,每组用例首先输入三个整数p,n,m分别表示敌人血量,A牌数,B牌数,之后m个整数ai表示第i张B牌的伤害值
(T<=10,p<=1000,n+m<=20,0< ai<=1000)
Output
对于每组用例,输出打败敌人的概率(输出最简分数形式)
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
Solution
因为最多20张牌,所以想到用一个20位二进制数表示一个状态,用dp[i]表示拿到牌的状态为i是否合法,初始化就是dp[1<< i]=1,i=0,1,…,n+m-1,对于一个状态i,如果已经拿到x张A牌和y张B牌,统计这y张B牌的总伤害,如果大于等于p则后面的牌随意排列都可以打败敌人,那么对答案的贡献就是dp[i]*(n+m-x-y)!,之后通过判断这个状态是否可以继续拿牌来转移到下一个状态,x张A牌可以拿2x张牌,去掉初始手中的一张牌,故若2x-x-y+1>0说明该状态可以接着拿牌,进而枚举这个状态中0的位赋为1即转移到一下状态
Code
有一个卡组,有两种卡牌,A牌n张,B牌m张,抽到一张A牌可以从卡组中再抽两张,抽到一张B牌可以给敌人造成一定的伤害,现在告诉敌人的血量P以及m张B牌的伤害值,初始状态可以从卡组中拿一张牌,问有多大概率可以打败敌人(即抽到牌的总伤害值大于等于敌人的血量)
Input
第一行一整数T表示用例组数,每组用例首先输入三个整数p,n,m分别表示敌人血量,A牌数,B牌数,之后m个整数ai表示第i张B牌的伤害值
(T<=10,p<=1000,n+m<=20,0< ai<=1000)
Output
对于每组用例,输出打败敌人的概率(输出最简分数形式)
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
Solution
因为最多20张牌,所以想到用一个20位二进制数表示一个状态,用dp[i]表示拿到牌的状态为i是否合法,初始化就是dp[1<< i]=1,i=0,1,…,n+m-1,对于一个状态i,如果已经拿到x张A牌和y张B牌,统计这y张B牌的总伤害,如果大于等于p则后面的牌随意排列都可以打败敌人,那么对答案的贡献就是dp[i]*(n+m-x-y)!,之后通过判断这个状态是否可以继续拿牌来转移到下一个状态,x张A牌可以拿2x张牌,去掉初始手中的一张牌,故若2x-x-y+1>0说明该状态可以接着拿牌,进而枚举这个状态中0的位赋为1即转移到一下状态
Code
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; #define maxn ((1<<20)+11) ll f[maxn]; int cnt[maxn]; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } void init() { f[0]=1; for(int i=1;i<=20;i++)f[i]=1ll*i*f[i-1]; for(int i=0;i<(1<<20);i++) { cnt[i]=0; for(int j=0;j<20;j++) if(i&(1<<j))cnt[i]++; } } int T,p,n,m,v[22]; ll dp[maxn]; bool check(int x) { int ans=0; for(int i=n;i<n+m;i++) if(x&(1<<i))ans+=v[i-n]; if(ans>=p)return 1; return 0; } int main() { init(); scanf("%d",&T); while(T--) { scanf("%d%d%d",&p,&n,&m); for(int i=0;i<m;i++)scanf("%d",&v[i]); memset(dp,0,sizeof(dp)); for(int i=0;i<n+m;i++)dp[1<<i]=1; ll ans=0,N=1<<(n+m); for(int i=0;i<N;i++) { int tot=cnt[i],x=cnt[i&((1<<n)-1)],y=tot-x; if(check(i)) { ans+=dp[i]*f[n+m-tot]; continue; } if(x-y+1<=0)continue; for(int j=0;j<n+m;j++) if(!(i&(1<<j)))dp[i|(1<<j)]+=dp[i]; } ll g=gcd(ans,f[n+m]); printf("%I64d/%I64d\n",ans/g,f[n+m]/g); } }
相关文章推荐
- HDU 5816 Hearthstone (状压dp)
- HDU 5816 Hearthstone (状压dp)
- HDU 5816 Hearthstone (状压DP)
- hdu 5816 Hearthstone (状压dp)
- HDU 5816 Hearthstone(状态压缩DP+概率)
- HDU 5816 Hearthstone (Probability dp, Conbinations)
- hdu 5816 Hearthstone 状态dp
- hdu 5816 Hearthstone(状态压缩dp)
- HDU 5816 Hearthstone 概率dp
- Hdu-5816 Hearthstone(状态压缩DP)
- hdu 4539(状压dp)
- hdu 2686(状压dp)
- HDU 1992Tiling a Grid With Dominoes(状压dp)
- hdu 2686(状压dp)
- hdu 4539(状压dp)
- hdu 2167(状压dp)
- Travelling - HDU 3001 状压dp
- hdu 4539 郑厂长系列故事——排兵布阵 (状压DP)
- HDU 4084 Campus Design 状压dp
- hdu 4640(状压dp)