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. Caffe学习系列(22):caffe图形化操作工具digits运行实例

    上接:Caffe学习系列(21):caffe图形化操作工具digits的安装与运行 经过前面的操作,我们就把数据准备好了. 一.训练一个model 右击右边Models模块的” Images" ...

  2. 塔吊力矩限制器,塔吊黑匣子,塔吊电脑,tower crane

    塔机力矩限制器,tower crane 适用于各种类型的固定臂塔机和可变臂塔机 塔机力矩限制器是塔式起重机机械的安全保护装置,本产品采用32位高性能微处理器为硬件平台,软件算法采用国内最先进的三滑轮取 ...

  3. Theano2.1.15-基础知识之theano如何处理shapre信息

    来自:http://deeplearning.net/software/theano/tutorial/shape_info.html How Shape Information is Handled ...

  4. 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)

    在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...

  5. JAVA多线程(二)

    Synchronized的使用: (一)synchronized:  Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 当某个方法或者代 ...

  6. 一键系统优化15项脚本,适用于Centos6.x

    #!/bin/sh ################################################ #Author:nulige # qqinfo:1034611705 # Date ...

  7. HIbernate的增删改

    数据库是oracle 以一对多为例:user50一的一方      order50是多的一方 首先是实体类: 这里的实体是双向关系,既通过user50可以找到order50,通过order50可以找到 ...

  8. 导入dmp文件时的注意事项

    来源于:http://bbs.csdn.net/topics/350167817 --1表空间 CREATE TABLESPACE newjw DATAFILE 'E:\oracle_data\new ...

  9. extJs学习基础

    显示和隐藏 所有的组件都是在show和hide方法中构造的.用来隐藏组件的默认的css方法是“display:none”但是通过hidemode配置的时候就有所变化了: Ext.onReady(fun ...

  10. Windows配置mycat

    MyCat使用Mysql的通讯协议模拟成一个MySQl服务器,并建立了完整的Schema(数据库).Table(数据表).User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNod ...