[ZOJ3329] One Person Game
Posted qixingzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZOJ3329] One Person Game相关的知识,希望对你有一定的参考价值。
传送门:>出错啦<
题意:有三个骰子,每个骰子分别有$k_1,k_2,k_3$面,若三个骰子分别骰到a, b, c则计数器归0,否则计数器加上三个骰子得到的数之和。求计数器达到n及以上所需要骰的次数的期望。
解题思路:
继续期望DP。
$f[i]$表示从i分到达n分所需要骰的次数的期望,因此$f[n] = 0$ 答案为$f[0]$
设骰一次(三个骰子之和)骰到$k$分的概率为$p[k]$,$p[0]$的概率即为骰到$a,b,c$的概率,只有$frac{1}{k_1*k_2*k_3}$。另外的累积一下可能性,也除以总可能性就可以了。
由i分转移到i+j分,分别加上相应的概率。并且还要特殊处理计数器清0的情况:清零的可能性乘以0分的期望。于是我们很容易得到方程:$$f[i] = sumlimits_{j=1 j != a+b+c}^{k_1+k_2+k_3}(p[j] * f[i+j]) + f[0] * p[0] + 1$$
但是注意,$f[0]$是我们要求的答案,怎么反而用来转移了?所以这个方程很不可行……
但是在这个递推式中,除了$f[0]$之外都是已知的,所以我们可以把它看做一个关于$f[0]$一次函数:$$f[i] = k * f[0] + b$$
并且我们发现系数只与$i$有关,所以$$f[i] = A[i] * f[0] + B[i]$$
因此可以替换$f[i+j]$:$$f[i] = sumlimits_{j=1 j != a+b+c}^{k_1+k_2+k_3}(p[j] * (A[i+j] * f[0] + B[i+j])) + f[0] * p[0] + 1$$
因此$$A[i] = A[i+j] * p[j] + p[0]$$$$B[i] = B[i+j] * p[j] + 1$$
特殊的,当$i == 0$时:$$f[0] = A[0] * f[0] + B[0]$$
也就是$$f[0] = frac{B[0]}{1 - A[0]}$$
这就是答案
Code
不要先做完再memset了
/*By QiXingzhi*/ #include <cstdio> #include <queue> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int N = 1010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w; } int n,a,b,c,k1,k2,k3,T; double p[N],A[N],B[N]; inline void Solve(){ p[0] = (double)1.0 / (double)(k1*k2*k3); for(int k = 3; k <= k1 + k2 + k3; ++k) p[k] = 0.0; // printf("p[0] = %.5lf ",p[0]); for(int i = 1; i <= k1; ++i){ for(int j = 1; j <= k2; ++j){ for(int k = 1; k <= k3; ++k){ if(i==a && j==b && k==c) continue; p[i+j+k] += 1.0; // printf("P[%d] = %d ",i+j+k,P[i+j+k]); } } } for(int k = 3; k <= k1+k2+k3; ++k){ p[k] = (double)(p[k]) / (double)(k1*k2*k3); } for(int i = n; i >= 0; --i){ A[i] = 0.0; B[i] = 0.0; } for(int i = n; i >= 0; --i){ for(int j = 3; j <= k1+k2+k3; ++j){ if(i + j > n) continue; A[i] += A[i+j] * p[j]; B[i] += B[i+j] * p[j]; } A[i] += p[0]; B[i] += 1.0; // printf("A[%d] = %.5lf B[%d] = %.5lf ",i,A[i],i,B[i]); } printf("%.15lf ", (double)(B[0]) / (double)(1.0 - A[0])); } main(){ // freopen(".in","r",stdin); T = r;a while(T--){ n = r; k1 = r, k2 = r, k3 = r; a = r, b = r, c = r; Solve(); } return 0; }
以上是关于[ZOJ3329] One Person Game的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ 3329:One Person Game 概率DP求期望(有环)