HDU 5816 Hearthstone
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
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.
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.
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.
Solution:
我第一发 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);
}
}
#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的更多相关文章
- HDU 5816 Hearthstone 概率dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5816 Hearthstone Time Limit: 2000/1000 MS (Java/Othe ...
- HDU 5816 Hearthstone (状压DP)
Hearthstone 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an onlin ...
- HDU 5816 状压DP&排列组合
---恢复内容开始--- Hearthstone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java ...
- HDU5816 Hearthstone(状压DP)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collec ...
- HDOJ 2111. Saving HDU 贪心 结构体排序
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【HDU 3037】Saving Beans Lucas定理模板
http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...
- hdu 4859 海岸线 Bestcoder Round 1
http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...
- HDU 4569 Special equations(取模)
Special equations Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u S ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...
随机推荐
- MPI+WIN10并行试运行
系统:2015 win10专业版 x64 MPI安装包:mpich2-1.4.1p1-win-x86-64.man 将后缀改为.msi 以管理员身份安装 安装过程一路默认,注意<behappy为 ...
- C#基础之泛型
1.泛型的本质 泛型的好处不用多说,在.NET中我看到有很多技术都是以泛型为基础的,不过因为不懂泛型而只能对那些技术一脸茫然.泛型主要用于集合类,最主要的原因是它不需要装箱拆箱且类型安全,比如很常用的 ...
- 告别编译运行 ---- Android Studio 2.0 Preview发布Instant Run功能
以往的Android开发有一个头疼的且拖慢速度的问题,就是你每改一行代码要想看到结果必须要编译运行到手机或者模拟器上,而且需要从头(可能是登录界面)一直点击到你修改的界面为止.开发一个完整的Andro ...
- 理解Android虚拟机体系结构
1 什么是Dalvik虚拟机 Dalvik是Google公司自己设计用于Android平台的Java虚拟机,它是Android平台的重要组成部分,支持dex格式(Dalvik Executable)的 ...
- web性能优化——简介
简介 性能优化的第一准则:加缓存.几乎绝大部分优化都围绕这个来进行的.让用户最快的看到结果. 性能优化的第二准则:最小原则.绝不提供多余的信息.比如,静态资源(图片.css.js)压缩,图片的滚动加载 ...
- Ext.NET-基础篇
概述 本文介绍Ext.NET的基本概念,安装配置.布局以及容器,最后介绍了DirectEvents.DirectMethod.Listener,并提供了示例代码. 示例代码下载地址>>&g ...
- 【python】 [基础] 数据类型,字符串和编码
python笔记,写在前面:python区分大小写1.科学计数法,把10用e代替,1.23x10·9就是 1.23e9 或者 0.00012就是1 ...
- 既不删除, 也不生成DS_store
defaults write com.apple.desktopservices DSDontWriteNetworkStores true sudo find / -name ".DS_S ...
- Android下常见的四种对话框
摘要:在实际开发过程有时为了能够和用户进行很好的交互,需要使用到对话框,在Android中常用的对话框有四种:普通对话框.单选对话框.多选对话框.进度对话框. 一.普度对话框 public void ...
- 我的第一个jsp程序-实现注册登录留言功能
1,注册功能,包括两个页面 zhuce.jsp注册页面 <%@ page language="java" contentType="text/html; chars ...