动态规划(Hearthstone,HDU 5816)
来源:互联网 发布:excel2013解密软件 编辑:程序博客网 时间:2024/06/03 18:23
看到N,M都很小,一开始想到了暴力搜索+剪枝可以枚举出能够完成击杀的牌的组合,计算量最多为2^20=1e6,(看到网上用状压来枚举,虽然不带剪枝,但是常数应该更小)。
然后在深入考虑预估函数的剪枝效率时,发现P也很小,好像可以动态规划。
dp[i][j][k]表示对于前i张火球术,恰选j张,恰打出k点伤害的概率,dp完后后缀和一下就可以得到前i张火球术,恰选j张,打出大于等于k点伤害的概率。
这样∑dp[M][j][P]就是能够击杀的概率。
但是这样还不够,因为奥术智慧的数量会影响到你的摸牌。
如果没有奥术智慧,那么你只能打出一张火球术。
如果全都是奥术智慧,那么你打不出任何伤害。
适当数量的奥术智慧才能最大化伤害。
然后发现,摸牌的情况就那么几种。
要么就有牌没法摸了,要么就全模完了。
就是考虑把奥术智慧全部打出去,然后摸牌,直到没有奥术智慧了。
然后把火球术再一次性打出去。
情况:
共摸了1张牌,其中0张奥数智慧,结束。
共摸了3张牌,其中1张奥数智慧,结束。
共摸了5张牌,其中2张奥数智慧,结束。
。。。
共摸了N+M张牌,其中N张奥数智慧,结束。
所以dp[i][j]表示前i张牌有j张奥数智慧的概率。
然后看情况转移就好了。(允许摸牌,有牌可摸,乘以概率)
最后答案就是∑上述各种情况的概率乘以击杀的概率,最后一种情况不要算重了。
或者说就是枚举摸到k张火球术的概率乘以k张火球术能击杀的概率。
或者说就是枚举摸牌结束的情况,就知道有k张火球术,然后乘以k张击杀的概率。
后来发现dp[i][j][k]不好算概率,就决定dp方案数,然后除以组合数。
dp也不用求什么后缀和,直接把伤害大于等于P的方案数累加到伤害等于P的方案数中就好了。
最后情况有三种
1、奥数智慧不够用,全拿到都摸不完。
2、奥数智慧刚刚好,全拿到恰好全摸完。
3、奥数智慧太多了,全拿到打出去也摸不到牌了。
只有第3中情况我们需要额外算全部摸完的情况。
一开始dp[i][j][k]计算概率,写完后发现转移是错的,也没法转移,后来才改成方案数。
然后交上去RE,说是除零,分析后发现是最后枚举的时候没考虑到奥术智慧或者火球术不够多,除以了错误的数据,比如0。
改正后交上去WA,后来全部重新思考了一遍,发现是全摸完的情况没讨论对,所以算重或算漏了。
最后才AC。时间复杂度O(NMP),0ms过了。
希望以后能思考得更具体一点,比如说具体到dp该怎么转移,是否正确,最后答案该怎么计算,或不会重复或遗漏,然后再开始写代码。
代码
#include<stdio.h>#include<algorithm>using namespace std;typedef long long ll;const ll maxc = 25;const ll maxp = 1010;ll gcd(ll a,ll b){ return !b?a:gcd(b,a%b);}struct fs{ ll fz,fm; fs(ll fz=0,ll fm=1):fz(fz),fm(fm) { this->yuefen(); } void zero() { fz=0; fm=1; } void one() { fz=1; fm=1; } void yuefen() { ll GCD = gcd(fz,fm); fz/=GCD; fm/=GCD; } fs operator + (const fs& rhs) const { fs ret; ll GCD = gcd(fm,rhs.fm); ret.fm=fm/GCD*rhs.fm; ret.fz=rhs.fm/GCD*fz+fm/GCD*rhs.fz; ret.yuefen(); return ret; } fs operator * (const fs& rhs) const { fs ret; ret.fm=fm*rhs.fm; ret.fz=fz*rhs.fz; ret.yuefen(); return ret; } fs operator - (const fs& rhs) const { fs ret; ll GCD = gcd(fm,rhs.fm); ret.fm=fm/GCD*rhs.fm; ret.fz=rhs.fm/GCD*fz-fm/GCD*rhs.fz; ret.yuefen(); return ret; } fs operator / (const fs& rhs) const { fs ret; ret.fm=fm*rhs.fz; ret.fz=fz*rhs.fm; ret.yuefen(); return ret; } void prll() { printf("%lld/%lld\n",fz,fm); }};ll P,N,M;ll X[maxc];fs num[maxc][maxc];ll kill[maxc][maxc][maxp];ll C[maxc][maxc];void read(){ scanf("%lld %lld %lld",&P,&N,&M); for(ll i=1;i<=M;i++) scanf("%lld",X+i);}void getnum(){ for(ll i=0;i<=N+M;i++) for(ll j=0;j<=i;j++) num[i][j].zero(); num[0][0].one(); for(ll i=0;i<N+M;i++) for(ll j=0;j<=min(i,N);j++) if(i==0||(i-1)/2<j) { if(j<N) num[i+1][j+1]=num[i+1][j+1]+num[i][j]*fs(N-j,N+M-i); if(i-j<M) num[i+1][j]=num[i+1][j]+num[i][j]*fs(M-i+j,N+M-i); }}void getkill(){ for(ll i=0;i<=M;i++) for(ll j=0;j<=i;j++) for(ll k=0;k<=P;k++) kill[i][j][k]=0; kill[0][0][0]=1; for(ll i=0;i<M;i++) for(ll j=0;j<=i;j++) for(ll k=0;k<=P;k++) { kill[i+1][j+1][min(P,k+X[i+1])]=kill[i+1][j+1][min(P,k+X[i+1])]+kill[i][j][k]; kill[i+1][j][k]=kill[i+1][j][k]+kill[i][j][k]; }}void getC(){ C[0][0]=1; for(ll i=1;i<maxc;i++) { C[i][0]=1; for(ll j=1;j<=i;j++) C[i][j]=C[i-1][j]+C[i-1][j-1]; }}void prllnum(){ puts("----------"); puts("num"); for(ll i=1;i<=N+M;i++) { for(ll j=0;j<=min(i,N);j++) printf("%lld/%lld ",num[i][j].fz,num[i][j].fm); puts(""); } puts("----------");}void prllkill(){ puts("----------"); puts("kill"); for(ll i=1;i<=M;i++) { printf("i=%lld\n",i); for(ll j=0;j<=i;j++) { printf("j=%lld\n",j); for(ll k=0;k<=P;k++) printf("%lld ",kill[i][j][k]); puts(""); } puts(""); } puts("----------");}void prllC(){ for(ll i=0;i<maxc;i++) { for(ll j=0;j<=i;j++) printf("%lld ",C[i][j]); puts(""); }}void solve(){ read(); getnum(); //prllnum(); getkill(); //prllkill(); fs ans; for(ll i=1;i<=N+M;i+=2) { ll j = i/2; if(j>N) break; if(i-j>M) break; ans=ans+num[i][j]*fs(kill[M][i-j][P],C[M][i-j]); } if(N>=M) { ll i = N+M; ll j = N; ans=ans+num[i][j]*fs(kill[M][M][P],C[M][i-j]); } ans.prll();}int main(){ getC(); //prllC(); ll T; scanf("%lld",&T); while(T--) solve(); return 0;}
- 动态规划(Hearthstone,HDU 5816)
- [HDU 5816] Hearthstone (概率DP+状压)
- HDU 5816 Hearthstone (状压dp)
- HDU 5816 Hearthstone(概率DP+状压)
- HDU 5816 Hearthstone (状压dp)
- HDU 5816 Hearthstone (状压dp+概率)
- HDU 5816 Hearthstone(状压DP)
- HDU 5816 Hearthstone
- HDU 5816 Hearthstone
- HDU 5816 Hearthstone
- hdu 5816 Hearthstone (状压dp)
- hdu 5816 Hearthstone 状态dp
- HDU 5816 Hearthstone(状态压缩DP+概率)
- Hdu-5816 Hearthstone(状态压缩DP)
- HDU 5816 Hearthstone(多校第七场)
- HDU-5816-Hearthstone-DP+数学推导
- HDU 5816 Hearthstone (Probability dp, Conbinations)
- HDU 1421 (动态规划)
- (数学)HDU 6045 Is Derek lying?
- 非旋转treap 模板
- 用js写一个选项卡
- Mysql语句总结(1)
- FOJ--1046--Tempter of the Bone(dfs+奇偶剪枝)
- 动态规划(Hearthstone,HDU 5816)
- Faulty Odometer HDU
- 在 Linux 上配置 mongodb
- Banner简单使用
- git 拉取远程代码
- 2017 多校训练第二场 HDU 6045 Is Derek lying?
- POJ 3261 Milk Patterns 最长出现k次的子串长度(后缀数组)
- 2017年JavaScript框架---Top5
- AC自动机入门题目(HDU