HDU5816 Hearthstone(状压DP)

题目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=5816

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

分析

题目大概说有两种卡牌,使用A牌能从牌堆摸两张牌,使用B牌能对对方造成xi点伤害。在你的回合,你从牌堆摸一张牌,问能对对方造成p点及以上伤害的概率。

要求的其实就是能造成p点以上伤害的牌堆排列数/牌堆全排列数

全排列而且总数为20,这种就该想到尝试用状压DP。。

  • dp[S]表示已经摸的牌的集合为S的可行排列方案数

对于一个状态S,我们能从这个集合中已经摸的牌知道还能摸几张,即A的数目 * 2 - A的数目 - B的数目 + 一开始能摸的一张牌

考虑状态的转移,我是用我为人人实现的:从小到大枚举状态S,判断S是否合法,即S的方案数不为0且还能摸牌,然后通过S去更新S+i(i∉S)状态的值。另外如果S能造成的伤害已经大于等于p了,那就没必要去更新它能转移到的状态,因为还剩下的牌直接求全排列计算其贡献,这样也能避免重复计算。

最后就循环遍历各个合法的状态累加贡献,这个贡献就是dp值 * 还没摸的牌的全排列数。这样就求出能造成p点以上伤害的牌堆排列数,再和全排列数用GCD搞搞输出答案即可。

代码

#include<cstdio>
#include<cstring>
using namespace std;

long long fact[22]={1};

long long gcd(long long a,long long b){
	if(b==0) return a;
	return gcd(b,a%b);
}

int p,n,m,N,x[22];
long long d[1<<20];

int main(){
	for(int i=1; i<22; ++i) fact[i]=fact[i-1]*i;
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&p,&n,&m);
		N=n+m;
		for(int i=n; i<N; ++i){
			scanf("%d",&x[i]);
		}

		memset(d,0,sizeof(d));
		d[0]=1;
		for(int s=0; s<(1<<N); ++s){
			if(d[s]==0) continue;

			int A=0,B=0,damage=0;
			for(int i=n; i<N; ++i){
				if(s>>i&1){
					damage+=x[i];
					++B;
				}
			}
			if(damage>=p) continue;
			for(int i=0; i<n; ++i){
				if(s>>i&1) ++A;
			}

			if(A-B+1<=0) continue;

			for(int i=0; i<N; ++i){
				if(s>>i&1) continue;
				d[s^(1<<i)]+=d[s];
			}
		}

		long long xx=0,yy=fact[N];
		for(int s=0; s<(1<<N); ++s){
			if(d[s]==0) continue;
			int A=0,B=0,damage=0;
			for(int i=n; i<N; ++i){
				if(s>>i&1){
					damage+=x[i];
					++B;
				}
			}
			for(int i=0; i<n; ++i){
				if(s>>i&1) ++A;
			}
			if(damage>=p){
				xx+=d[s]*fact[N-A-B];
			}
		}
		long long g=gcd(xx,yy);
		printf("%I64d/%I64d\n",xx/g,yy/g);
	}
	return 0;
}
时间: 2024-10-18 19:46:43

HDU5816 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-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

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

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

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

BZOJ 1072 排列 状压DP

题意:链接 方法:状压DP? 题解:这题其实没啥好写的,不算很难,推一推就能搞出来. 首先看到这个问题,对于被d整除这个条件,很容易就想到是取余数为0,所以想到可能状态中刚开始含有取余数. 先说我的第一个想法,f[i][j]表示选取i个数且此时的mod为j,这样的思想是第一下蹦出来的,当时想的就是在线来搞最终的答案.不过转瞬即发现,这TM不就是暴力吗魂淡!并没有什么卵用,于是开始想这个状态可不可以做什么优化. 显然第二维的j并不需要太大的优化,暂且先将其搁置一边,来考虑第一维的i怎么优化. 把滚