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
 
Author
SYSU
 
Source

Solution:
状压DP.
我第一次设计的DP状态是:
$\text{dp}[s][i]:$ 当前已经抽得的卡的集合是 $s$, 还剩下 $i$ 次抽卡机会的方案数.
但是超内存了……算了一下, 发现这个 $\text{dp}$ 数组确实开不下, 后来想到 $i$ 只和 $s$ 有关, 也就意味着根本不需要 $\text{dp}$ 的第二维.
设 $s$ 中有 $x$ 张A-Card, $y$ 张B-Card, 那么剩余的抽卡次数就是 $2x+1-(x+y) = x-y+1$ ,但是这样改过之后就陷入了无尽的超时,这个做法的复杂度是 $O((m+n)2^{m+n})$ ,竟然卡常数……

我第一发 TLE 的 NAIVE 写法:

#include <bits/stdc++.h>
using namespace std; typedef long long LL; const int N{};
int T, n, m, p;
int a[N]; LL dp[<<]; int calc(int s){
int res=;
for(int i=; i<m; i++)
if(s&<<i) res+=a[i];
return res;
} int ones(int s){
int res=;
for(int i=; i<n+m; i++)
res+=bool(s&<<i);
return res;
} int r(int s){
int x=, y=;
for(int i=; i<(n+m); i++)
if(s&<<i){
x++;
if(i>=m) y++;
}
return *y+-x;
} // int main(){ LL f[N]{};
for(int i=; i<N; i++)
f[i]=f[i-]*i; for(cin>>T; T--; ){
cin>>p>>n>>m;
for(int i=; i<m; i++)
cin>>a[i]; int tot=m+n; memset(dp, , sizeof(dp));
dp[]=; for(int s=; s<<<tot; s++)
if(dp[s] &&r(s)>)
for(int j=; j<tot; j++)
if(!(s&<<j))
dp[s|<<j]+=dp[s]; LL res=;
int full=(<<tot)-; for(int s=; s<<<tot; s++)
if(calc(s)>=p && (r(s)== || s==full))
res+=dp[s]*f[tot-ones(s)]; // cout<<res<<endl; LL gcd=__gcd(res, f[tot]);
printf("%lld/%lld\n", res/gcd, f[tot]/gcd);
}
}
最后一发TLE的写法:
#include <bits/stdc++.h>
using namespace std; typedef long long LL; const int N{<<};
int T, n, m, p; int a[N], ones[<<]; LL dp[<<], f[N]{}; inline int calc(int s){
int res=;
for(int i=; i<m; i++)
if(s&<<i) res+=a[i];
return res;
} inline int r(int s){
int res=;
for(int i=; i<m; i++)
res+=bool(s&<<i);
// return 2*(ones[s]-res)+1-ones[s];
return ones[s]-(res<<)+;
} // int main(){ for(int i=; i<<<; i++)
for(int j=; j<; j++)
if(i&<<j) ones[i]++; for(int i=; i<N; i++)
f[i]=f[i-]*i; for(scanf("%d", &T); T--; ){
scanf("%d%d%d", &p, &n, &m);
for(int i=; i<m; i++)
scanf("%d", a+i); // LL res=0; int tot=m+n;
LL res=, full=(<<tot)-; if(calc(full)>=p){ memset(dp, , sizeof(dp));
dp[]=;
for(int s=; s<<<tot; s++)
if(dp[s])
if(r(s)== || s==full){
if(calc(s)>=p) res+=dp[s]*f[tot-ones[s]];
}
else{
for(int j=; j<tot; j++)
if(!(s&<<j))
dp[s|<<j]+=dp[s];
}
} LL gcd=__gcd(res, f[tot]);
printf("%lld/%lld\n", res/gcd, f[tot]/gcd);
}
}

这个写法赛后在题库中AC了, 跑了907ms...

AC的姿势:

#include <bits/stdc++.h>
using namespace std; typedef long long LL; const int N{<<};
int T, n, m, p; int a[N], ones[<<]; LL dp[<<], f[N]{}; inline int calc(int s){
int res=;
for(int i=; i<m; i++)
if(s&<<i) res+=a[i];
return res;
} inline int r(int s){
int res=;
for(int i=; i<m; i++)
res+=bool(s&<<i);
// return 2*(ones[s]-res)+1-ones[s];
return ones[s]-(res<<)+;
} // int main(){ for(int i=; i<<<; i++)
for(int j=; j<; j++)
if(i&<<j) ones[i]++; for(int i=; i<N; i++)
f[i]=f[i-]*i; for(scanf("%d", &T); T--; ){
scanf("%d%d%d", &p, &n, &m); for(int i=; i<m; i++)
scanf("%d", a+i); // LL res=0; int tot=m+n;
LL res=, full=(<<tot)-; if(calc(full)>=p){
memset(dp, , sizeof(dp));
dp[]=;
for(int s=; s<<<tot; s++)
if(dp[s])
if(calc(s)>=p) res+=dp[s]*f[tot-ones[s]];
else if(r(s)>)
for(int j=; j<tot; j++)
if(!(s&<<j))
dp[s|<<j]+=dp[s];
} LL gcd=__gcd(res, f[tot]);
printf("%lld/%lld\n", res/gcd, f[tot]/gcd);
}
}

这个跑了358ms.

Conclusion:

1. 剪枝

2. 预处理 $\text{ones}$ 表, $\mathrm{ones}[i]$ 表示 $i$ 的二进制表达式中$1$的个数.


这题应该还有复杂度更优的做法, 之后再补充.

 
 

HDU 5816 Hearthstone的更多相关文章

  1. HDU 5816 Hearthstone 概率dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5816 Hearthstone Time Limit: 2000/1000 MS (Java/Othe ...

  2. HDU 5816 Hearthstone (状压DP)

    Hearthstone 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an onlin ...

  3. HDU 5816 状压DP&排列组合

    ---恢复内容开始--- Hearthstone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java ...

  4. HDU5816 Hearthstone(状压DP)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collec ...

  5. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  6. 【HDU 3037】Saving Beans Lucas定理模板

    http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...

  7. hdu 4859 海岸线 Bestcoder Round 1

    http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...

  8. HDU 4569 Special equations(取模)

    Special equations Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

  9. HDU 4006The kth great number(K大数 +小顶堆)

    The kth great number Time Limit:1000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64 ...

随机推荐

  1. Linux下SVN安装与基本操作

    1.安装svn linux下通过yum安装svn yum -y install subversion 本地Windows系统安装TortoiseSVN 2.配置 建立版本库目录 mkdir /home ...

  2. Android系统启动分析(Init->Zygote->SystemServer->Home activity)

    整个Android系统的启动分为Linux Kernel的启动和Android系统的启动.Linux Kernel启动起来后,然后运行第一个用户程序,在Android中就是init程序. ------ ...

  3. web性能优化——浏览器相关

    简介 优化是一个持续的过程.所以尽可能的不要有人为的参与.所以能自动化的或者能从架构.框架级别解决的就最更高级别解决. 这样即能实现面对开发人员是透明的.不响应,又能确保所有资源都是被优化过的. 场景 ...

  4. Tyk API网关介绍及安装说明

    Tyk API网关介绍及安装说明 Tyk是一个开源的轻量级API网关程序. 什么是API网关 API网关是一个各类不同API的前置服务器.API网关封装了系统内部架构,对外提供统一服务.此外还可以实现 ...

  5. 高端大气上档次Ergotron Neo-Flex+MBP Retina的组合~

  6. VS2013 未找到与約束ContractName

    vs2013打开项目无法加载项目,关闭时提示  未找到与約束ContractName... 解決方法,打開控制面板,找到下面這個程序 右击,选 择 修 复

  7. Docker部署SDN环境

    2014-12-03 by muzi Docker image = Java class Docker container = Java object 前言 5月份的时候,当我还是一个大学生的时候,有 ...

  8. 准确率(Accuracy), 精确率(Precision), 召回率(Recall)和F1-Measure

    yu Code 15 Comments  机器学习(ML),自然语言处理(NLP),信息检索(IR)等领域,评估(Evaluation)是一个必要的 工作,而其评价指标往往有如下几点:准确率(Accu ...

  9. JS 页面加载触发事件 document.ready和window.onload的区别

    document.ready和onload的区别——JavaScript文档加载完成事件页面加载完成有两种事件: 一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件): 二是onlo ...

  10. mybatis字符串模糊匹配

    1.  参数中直接加入%%,注意不需要加两个单引号,加了就会出错,因为系统会自动为字符串类型加上两个单引号 <select id="selectPersons" result ...