[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的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ3329One Person Game

ZOJ 3329:One Person Game 概率DP求期望(有环)

[ZOJ3329] One Person Game

ZOJ 3329 One Person Game

ZOJ3329One Person Game(循环型 数学期望)

ZOJ 3329 One Person Game——期望DP