【NOI2017模拟.4.1】 Dice【概率,期望,DP,精度优化】

20 篇文章 0 订阅
16 篇文章 0 订阅

Description

这里写图片描述

Solution

这道题的期望转移其实不难,但是精度很难卡。
先考虑第一个答案

g[i][j]ij
f[i][j]ij
g[i][j]=kpg[i1][k]P
p是条件概率为前提是选了k,然后在选到j的概率。
P有两种推法:
1、直接照着含义推,因为现在要是j在前面是k的前提下成功,所以不是k的情况为 (1p[k]) ,然后选到j在其中的概率为 P=p[j]1p[k]
2、因为选到j就停了,不能选到k,所以选到k就继续选,那么 P=p[j]+Pp[k] ,变化一下 P=p[j]1p[k]
然后期望就很简单了,直接用概率乘上权值就好了。
但是下面的方差的概率怎么办。
我们设已经求出来了ans。
那么要求 E((ansx)2)=E(ans2)2ansE(x)E(x2)
所以现在问题就变成求平方的期望就可以了,这个和直接求期望差不多,只是转移的时候要注意一下是从 a2>(a+b)2=a2+2ab+b2
但是求出来之后,会得到一下精度比较大的数,如果直接减的话精度会影响比较大,所以考虑一下后面的减号能不能化掉。
E((ansx)2)=E((ansxi)2)
假如能直接把这里的减号给化掉就很好了。
=E(ans22ansxi+xi2)=E(ans2)E(ansxi)+E(xi2)
我们发现如果 xi=ans 的话,那么就可以消去影响。
那么
E(ans2)E(ansxi)+E(xi2)=E(ans2)E(ansnansn)+E((xiansn)2)=E((xansn)2)
所以我们把每个 xiansn ,再求平方的期望就可以了。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef double db;
const int maxn=1e5+7;
int i,j,k,l,t,n,m,pp,q;
db p[7],f[maxn][7],g[maxn][7],s[maxn][7],ans,ans1,x;
int main(){
    freopen("dice.in","r",stdin);
    freopen("dice.out","w",stdout);
 //   freopen("fan.in","r",stdin) ;
    fo(i,1,6)scanf("%lf",&p[i]),f[1][i]=p[i]*i,g[1][i]=p[i],s[1][i]=p[i]*i*i;
    scanf("%d",&n);
    fo(i,2,n){
        fo(j,1,6){
            fo(k,1,6){
                if(j==k)continue;
                g[i][j]+=g[i-1][k]*p[j]/(1-p[k]);
                f[i][j]+=f[i-1][k]*p[j]/(1-p[k]);
            }
            f[i][j]+=g[i][j]*j;

        }
    }
    fo(i,1,6)ans+=f[n][i];
    printf("%.7lf\n",ans);
    memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(s,0,sizeof(s));
    x=ans/n;
    fo(i,1,6)f[1][i]=p[i]*(i-x),g[1][i]=p[i],s[1][i]=p[i]*(i-x)*(i-x);
    fo(i,2,n){
        fo(j,1,6){
            fo(k,1,6){
                if(j==k)continue;
                g[i][j]+=g[i-1][k]*p[j]/(1-p[k]);
                f[i][j]+=f[i-1][k]*p[j]/(1-p[k]);
                s[i][j]+=s[i-1][k]*p[j]/(1-p[k]);
            }
            s[i][j]+=g[i][j]*(j-x)*(j-x)+2*f[i][j]*(j-x);
            f[i][j]+=g[i][j]*(j-x);

        }
    }
    fo(i,1,6)ans1+=s[n][i];
    printf("%.7lf\n",ans1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值