您的位置:首页 > 其它

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

2017-04-07 10:28 363 查看

Description



Solution

这道题的期望转移其实不难,但是精度很难卡。

先考虑第一个答案



g[i][j]为取到第i次,取得数为j的概率

f[i][j]为取到第i次,取得数为j的期望

g[i][j]=∑k≠pg[i−1][k]∗P

p是条件概率为前提是选了k,然后在选到j的概率。

P有两种推法:

1、直接照着含义推,因为现在要是j在前面是k的前提下成功,所以不是k的情况为(1−p[k]),然后选到j在其中的概率为P=p[j]1−p[k]。

2、因为选到j就停了,不能选到k,所以选到k就继续选,那么P=p[j]+P∗p[k],变化一下P=p[j]1−p[k]

然后期望就很简单了,直接用概率乘上权值就好了。

但是下面的方差的概率怎么办。

我们设已经求出来了ans。

那么要求E((ans−x)2)=E(ans2)−2∗ans∗E(x)−E(x2)

所以现在问题就变成求平方的期望就可以了,这个和直接求期望差不多,只是转移的时候要注意一下是从a2−−>(a+b)2=a2+2ab+b2。

但是求出来之后,会得到一下精度比较大的数,如果直接减的话精度会影响比较大,所以考虑一下后面的减号能不能化掉。

E((ans−x)2)=E((ans−xi)2)

假如能直接把这里的减号给化掉就很好了。

=E(ans2−2ansxi+xi2)=E(ans2)−E(ans∑xi)+∑E(xi2)

我们发现如果∑xi=ans的话,那么就可以消去影响。

那么

E(ans2)−E(ans∑xi)+∑E(xi2)=E(ans2)−E(ans∗n∗ansn)+∑E((xi−ansn)2)=E((x−ansn)2)

所以我们把每个xi减去ansn,再求平方的期望就可以了。

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
[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
[i];
printf("%.7lf\n",ans1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: