【jzoj100004】【Dice】【数学期望】

题目大意

【jzoj100004】【Dice】【数学期望】_第1张图片

解题思路

Var[X]=E[(XE[X])2]=E[X2+E[X]22XE[X]]=E[X2]E[X]2 设F[i][j]表示第i次出现j的期望和。E[i][j]表示表示第i次出现j的概率和。G[i][j]表示第i次出现j的和的平方的期望。E,F的转移很好推, G[i+1][k]+=(G[i][j]+2F[i][j]k+kkE[i][j])P[k]/(1P[j]);

由于E[X^2]-E[X]^2的精度误差很大,我们考虑 Var[X]=E[(XE[X])2]=E[(XCE[XC])2]=E[(XC(E[X]C))2] 我们发现这种变换是等价的,但是使E[X]^2变为零,这样就减少了精度误差。实践时只需将掷出的数减去E[X]/N即可。

code

#include
#include
#include
#include
#include
#define LF double
#define LL long long
#define Min(a,b) ((a
#define Max(a,b) ((a>b)?a:b)
#define Fo(i,j,k) for(int i=j;i<=k;i++)
#define Fd(i,j,k) for(int i=j;i>=k;i--)
#define For(i,j) for(int i=Begin[j];i;i=Next[i])
using namespace std;
int const Mxn=1e5+9;
int N;LF P[9],E[Mxn][9],F[Mxn][9],G[Mxn][9];
int main(){
    //freopen("dice.in","r",stdin);
    //freopen("dice.out","w",stdout);
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    Fo(i,1,6)scanf("%lf",&P[i]);
    scanf("%d",&N);
    Fo(i,1,6)E[1][i]=P[i],F[1][i]=i*P[i],G[1][i]=i*i*P[i];
    Fo(i,1,N-1)Fo(j,1,6)Fo(k,1,6)if(j!=k)
        E[i+1][k]+=E[i][j]*P[k]/(1-P[j]),
        F[i+1][k]+=(F[i][j]+k*E[i][j])*P[k]/(1-P[j]);
    LF Ans1=0;
    Fo(i,1,6)Ans1+=F[N][i];
    printf("%.12lf\n",Ans1);Ans1/=N;
    Fo(i,1,N)Fo(j,1,6)F[i][j]=G[i][j]=0;
    Fo(i,1,6)F[1][i]=(i-Ans1)*P[i],G[1][i]=(i-Ans1)*(i-Ans1)*P[i];
    Fo(i,1,N-1)Fo(j,1,6)Fo(k,1,6)if(j!=k)
        F[i+1][k]+=(F[i][j]+(k-Ans1)*E[i][j])*P[k]/(1-P[j]),
        G[i+1][k]+=(G[i][j]+2*F[i][j]*(k-Ans1)+(k-Ans1)*(k-Ans1)*E[i][j])*P[k]/(1-P[j]);
    LF Ans2=0;
    Fo(i,1,6)Ans2+=G[N][i];
    printf("%.12lf",Ans2);
    return 0;
}

你可能感兴趣的:(期望,jzoj)