【JZOJ100004】【NOI2017模拟.4.1】 Dice

任务

这里写图片描述
这里写图片描述

解法

我们分开考虑每个骰子的贡献;
Xi 表示第 i 个骰子的点数。
显然Ans1=ni=1E[Xi]
E[Xi]=6j=1jP[Xi=j]
但题目要求我们不能连续两次投相同的骰子;
所以 P[Xi=j]=6k=1P[Xi1=k]P[Xi=j|Pi1=k] ,其中 i>1

P[Xi=j|Pi1=k]={0,pj+pkP[Xi=j|Pi1=k],j=kj=k

所以 P[Xi=j|Pi1=k]=pj1pk


我们知道 E[Ans1] 后,要求 Ans2=E[(Ans1E[Ans1])2]
也即 Ans2=E[(XiE[Ans1])2]
由于 E[Ans1] 是常量,我们先让 XiE[ans1]n ,则有 Ans2=E[(Xi)2]
所以

E[Ans2]=E[(Xi)2]=E[i=1nj=1nXiXj]=E[i=1n(Xi)2]+2E[i=1nj=i+1nXiXj]

容易算出 E[ni=1(Xi)2]
我们考虑 E[ni=1nj=i+1XiXj]
E[i=1nj=i+1nXiXj]=i=1nj=i+1nk=16l=16klP[Xi=k]P[Xj=l|Xi=k]=k=16l=16kli=1nj=i+1nP[Xi=k]P[Xj=l|Xi=k]=k=16l=16kli=1nP[Xi=k]j=i+1nP[Xj=l|Xi=k]=k=16l=16kli=1nP[Xi=k]j=1ni+1P[Xj=l|X1=k]

由于 ni+1j=1P[Xj=l|X1=k] 只与三元有关,所以可以预处理。

代码

#include<iostream>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<string.h>
#define ll long long
#define db double
using namespace std;
const char* fin="dice.in";
const char* fout="dice.out";
const int inf=0x7fffffff;
const int maxn=100007;
int n,m,i,j,k,l;
db p[7],ans1=0,ans2=0,oo;
db f[maxn][7],g[7][7][maxn],h[7][7][maxn];
int main(){
    freopen(fin,"r",stdin);
    freopen(fout,"w",stdout);
    for (i=1;i<=6;i++) scanf("%lf",&p[i]);
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        for (j=1;j<=6;j++)
            if (i==1) f[i][j]=p[j];
            else for (k=1;k<=6;k++) 
                if (j!=k) f[i][j]+=f[i-1][k]*(p[j]/(1-p[k]));
    for (i=1;i<=n;i++) for (j=1;j<=6;j++) ans1+=f[i][j]*j;
    printf("%lf\n",ans1);
    for (i=1;i<=6;i++) for (j=1;j<=6;j++){
        if (i!=j){
            g[i][j][2]=p[j]/(1-p[i]);
            h[i][j][2]=g[i][j][2];
        }
    }
    for (k=3;k<=n;k++){
        for (i=1;i<=6;i++) for (j=1;j<=6;j++){
            for (l=1;l<=6;l++){
                if (j!=l){
                    g[i][j][k]+=g[i][l][k-1]*(p[j]/(1-p[l]));
                }
                h[i][j][k]=g[i][j][k]+h[i][j][k-1];
            }
        }
    }
    db C=ans1/n;
    for (k=1;k<=6;k++)
        for (l=1;l<=6;l++)
            for (i=1;i<n;i++)
                ans2+=(k-ans1/n)*(l-ans1/n)*f[i][k]*h[k][l][n-i+1];
    ans2*=2;
    for (i=1;i<=n;i++) for (j=1;j<=6;j++) ans2+=(j-ans1/n)*(j-ans1/n)*f[i][j];
    printf("%lf\n",ans2);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值