Pokemon Ultra Sun
两只pokemon对战 A有hp1血量B有hp2血量
每回合A有p的概率对B造成w的伤害
或者B有1-p的概率对A造成w的伤害
当有一方血量低于或等于0时结束
问对战回合(轮数)的期望值
首先需要知道求期望的一般公式 $Exp=∑_{i=0}^{n}i×p_i$
对于此题轮数的期望值= 1轮结束的概率×1+2轮结束的概率×2+….n轮结束的概率×n
例如样例:
hp1=3,hp2=1,w=1
p=0.8
第一轮结束的局面有(3,0),对应概率为0.8
第二轮结束的局面有(2,0),对应概率为0.2×0.8
第三轮结束的局面有(1,0),(0,1) 对应概率为0.2×0.2×0.8 和 0.2×0.2×0.2
所以 $Exp=1×0.8+2×0.2×0.8+3×(0.2×0.2×0.8 和 0.2×0.2×0.2)$
上图对于局面状态(概率)的转移就已经显而易见了
设计dp(i,j)表示到达A剩余i血 B剩余j血的局面概率
更新完dp后根据期望公式直接求得答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <bits/stdc++.h> using namespace std; typedef long long ll; #define endl '\n' #define Turnoff std::ios::sync_with_stdio(false) #define P pair<ll,ll> const int Max=2e5+5; const int Mod=1e9+7; const int inf=0x3f3f3f3f;
double dp[3005][3005]; int main(){ int q;scanf("%d",&q); while(q--){ int hp1,hp2,w; double p; scanf("%d %d %d %lf",&hp1,&hp2,&w,&p); memset(dp,0,sizeof dp); dp[hp1][hp2]=1; int A=ceil(1.0*hp1/w),B=ceil(1.0*hp2/w); for(int i=0;i<=A;i++){ for(int j=0;j<=B;j++){ if(j&&hp1-i*w>0&&hp2-(j-1)*w>0)dp[max(0,hp1-i*w)][max(0,hp2-j*w)]+=dp[hp1-i*w][hp2-(j-1)*w]*p; if(i&&hp1-(i-1)*w>0&&hp2-j*w>0)dp[max(0,hp1-i*w)][max(0,hp2-j*w)]+=dp[hp1-(i-1)*w][hp2-j*w]*(1-p); } } double ans=0; for(int i=1;i<=hp1;i++){ if((hp1-i)%w)continue; int round=(hp1-i)/w+B; ans+=dp[i][0]*round; } for(int j=1;j<=hp2;j++){ if((hp2-j)%w)continue; int round=(hp2-j)/w+A; ans+=dp[0][j]*round; } printf("%.6f\n",ans); } }
|