多校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 #include <bits/stdc++.h>
 10 using namespace std;
 11 #define LL long long
 12 const int inf = 0x3f3f3f3f;
 13 const int MOD =998244353;
 14 const int N =200010;
 15 #define clc(a,b) memset(a,b,sizeof(a))
 16 const double eps = 1e-7;
 17 void fre() {freopen("in.txt","r",stdin);}
 18 void freout() {freopen("out.txt","w",stdout);}
 19 inline int read() {int x=0,f=1;char ch=getchar();while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) f=-1;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();}return x*f;}
 20 int n,m,p;
 21 LL dp[1<<21];
 22 int B[21];
 23 LL fac[21]={1};
 24 int main(){
 25     fac[0]=1;
 26     for(int i=1;i<21;i++) fac[i]=fac[i-1]*i;
 27     int T,sum,a,b;
 28     scanf("%d",&T);
 29     while(T--){
 30         scanf("%d%d%d",&p,&n,&m);
 31         int N=n+m;
 32         for(int i=0;i<1<<N;i++) dp[i]=0;
 33         for(int i=n;i<N;i++) scanf("%d",&B[i]);
 34
 35         dp[0]=1,sum=0,b=0,a=0;
 36         for(int i=0;i<1<<N;i++){
 37             if(dp[i]==0) continue;
 38             sum=0,a=0,b=0;
 39             for(int j=n;j<N;j++){
 40                 if(i&(1<<j)){
 41                    sum+=B[j];
 42                    b++;
 43                 }
 44             }
 45             if(sum>=p)continue;
 46             for(int j=0;j<n;j++){
 47                 if(i&(1<<j)){
 48                     a++;
 49                 }
 50             }
 51             if(a-b+1<=0) continue;
 52             for(int j=0;j<N;j++){
 53                 if((i&(1<<j))==0){
 54                     dp[i|(1<<j)]+=dp[i];
 55                 }
 56             }
 57         }
 58         LL Den=fac[N],Mol=0;
 59         for(int i=0;i<(1<<N);i++){
 60             a=0,b=0,sum=0;
 61             for(int j=n;j<N;j++){
 62                 if(i&(1<<j)){
 63                     b++;sum+=B[j];
 64                 }
 65             }
 66             if(sum<p) continue;
 67             for(int j=0;j<n;j++){
 68                 if(i&(1<<j)){
 69                     a++;
 70                 }
 71             }
 72             Mol+=(LL)dp[i]*fac[N-b-a];
 73         }
 74         LL g=__gcd(Mol,Den);
 75         printf("%I64d/%I64d\n",Mol/g,Den/g);
 76     }
 77     return 0;
 78 }
 79
 80
 81
 82 解法2标程:O(2^m)
 83 f[i][j]表示A拿i张,B拿j张的方案数
 84 方法用f[i][j]表示A类牌和B类牌分别抽到i张和j张,且抽牌结束前保证i>=j的方案数,这个数组可以用O(n^2)的dp预处理得到.
 85 接下来枚举B类牌的每个子集,如果这个子集之和不小于P,用k表示子集的1的个数,将方案总数加上取到这个集合刚好A类卡片比B类卡片少一(过程结束)的方案数:f[k-1][k] * C(n, k - 1) * (k - 1)! * k! * (n + m – 2*k + 1)! .
 86 如果子集包含了所有的B类卡片,则还需要再加上另一类取牌结束的情况,也就是取完所有牌,此时应加上的方案数为f[n][m] * n! * m! .
 87 最后的总方案数除以(n+m)!就是答案.
 88
 89
 90 #include <cstdio>
 91 typedef long long lli;
 92
 93 int bc[1<<20], sum[1<<20], tmp[1<<20];
 94 int C[21][21];
 95 lli f[21][21], fact[21];
 96
 97 lli gcd(lli a, lli b)
 98 {
 99     if (b == 0) return a;
100     return gcd(b, a % b);
101 }
102
103 void init()
104 {
105     int i, j;
106     bc[0] = 0;
107     for (i=1; i<(1<<20); i++) bc[i] = bc[i^(i&-i)] + 1;
108     fact[0] = 1;
109     for (i=1; i<=20; i++) fact[i] = fact[i-1] * i;
110     C[0][0] = 1;
111     for (i=1; i<=20; i++)
112     {
113         C[i][0] = C[i][i] = 1;
114         for (j=1; j<i; j++) C[i][j] = C[i-1][j] + C[i-1][j-1];
115     }
116     f[0][0] = f[0][1] = 1;
117     for (i=1; i<=20; i++)
118     {
119         f[i][0] = 1;
120         for (j=1; j<i; j++) f[i][j] = f[i-1][j] + f[i][j-1];
121         f[i][i] = f[i][i+1] = f[i][i-1];
122     }
123 }
124
125 int main()
126 {
127     lli a, b, d;
128     int p, n, m, t, i;
129     init();
130     scanf("%d", &t);
131     while (t --)
132     {
133         scanf("%d %d %d", &p, &n, &m);
134         for (i=0; i<m; i++) scanf("%d", &tmp[1<<i]);
135         sum[0] = 0;
136         for (i=1; i<(1<<m); i++) sum[i] = sum[i^(i&-i)] + tmp[i&-i];
137         a = 0;
138         for (i=0; i<(1<<m); i++)
139         {
140             if (sum[i] >= p && bc[i] <= n + 1)
141             {
142                 a += C[n][bc[i]-1] * f[bc[i]-1][bc[i]] * fact[bc[i]-1] * fact[bc[i]] * fact[n+m-2*bc[i]+1];
143                 if (bc[i] == m && bc[i] < n + 1) a += f[n][m] * fact[n] * fact[m];
144             }
145         }
146         b = fact[n+m];
147         d = gcd(a, b);
148         printf("%I64d/%I64d\n", a / d, b / d);
149     }
150     return 0;
151 }
时间: 2024-09-28 19:05:38

多校7 HDU5816 Hearthstone 状压DP+全排列的相关文章

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

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 an

[hdu 4899]14年多校第四场C Hero meet devil 状压DP

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 122    Accepted Submission(s): 49 Problem Description There is an old country and the king fell in love with a devil. The devil always asks th

【弱校胡策】2016.4.14 (bzoj2164)最短路+状压DP+矩阵乘法+高斯消元+树链剖分+线段树+背包DP

cyyz&qhyz&lwyz&gryz弱校胡策 命题人:cyyz ws_fqk T3暴力写挫了 50+10+0滚粗辣! 奇妙的约会(appointment.cpp/c/pas) [问题描述] DQS和sxb在网上结识后成为了非常好的朋友,并且都有着惊人 的OI水平.在NOI2333的比赛中,两人均拿到了金牌,并保送进入 HU/PKU.于是两人决定在这喜大普奔的时刻进行面基. NOI2333参赛选手众多,所以安排了n个考点,DQS在1号考点, 而sxb在n号考点.由于是举办全国性赛事

2015广东工业大学ACM校赛 I 游戏王 (状压dp)

Problem I: 游戏王 Description 小学的时候,Stubird非常喜欢玩游戏王,有一天,他发现了一个绝佳的连锁组合,这个连锁组合需要6张卡, 可是他一张都没有,但是他的那些朋友们有,不过当然,他们不会白给,不过也不排除有人和他交情好,送给他了. 不过他们有成全别人的美德,当他们看到Stubird已经有某些他们喜欢的卡的时候,他们会给他优惠,或者更贵也说不定 嘛不过,你可以把有的卡片藏起来,不告诉他们,来获得更低的价格. 问他最少需要多少钱才可以集齐所有的卡. Input 第一行

nefu1109 游戏争霸赛(状压dp)

题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰的人用0表示.倒着循环即可. //比赛的时候我用的是二维dp数组表示状态,一直是WA的,搞不懂原因...Orz... 代码: #include<iostream> #include<cstdio> #include<algorithm> #include<cstrin

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