[ZOJ3329]One Person Game(概率dp)

本文介绍了一种使用动态规划解决特定类型的数学期望问题的方法。通过构建概率转移方程,利用DP预处理技巧,解决了给定得分时游戏结束的期望值计算难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

传送门

题解

令f(i)表示得分为i时到结束的期望
显然这道题>0的点都可以从0转移过来,0也可以从每一个>0的点转移过来
所以这题就应该画柿子
f(i)=f(i+k)p(k)+f(0)P+1 ,其中p(i)表示掷出和为i的骰子的概率,P表示掷出a,b,c的概率
每一项都包含f(0),令f(i)=pa(i)f(0)+pb(i),那么f(i+k)=pa(i+k)f(0)+pb(i+k)
将其代入 f(i)=(pa(i+k)f(0)+pb(i+k))p(k)+f(0)P+1
f(i)=(pa(i+k)p(k)+P)f(0)+pb(i+k)p(k)+1
得到 pa(i)=pa(i+k)p(k)+P pb(i)=pb(i+k)p(k)+1
然后就可以dp出pa和pb了
最终 f(0)=pb(0)1pa(0)

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

int T,n,k1,k2,k3,a,b,c;
double P,ans,p[50],pa[1005],pb[1005];

void clear()
{
    n=k1=k2=k3=a=b=c=0;
    P=ans=0;
    memset(p,0,sizeof(p));memset(pa,0,sizeof(pa));memset(pb,0,sizeof(pb));
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        clear();
        scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
        P=1.0/((double)k1*(double)k2*(double)k3);
        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) p[i+j+k]+=P;
        for (int i=n;i>=0;--i)
        {
            for (int j=3;j<=k1+k2+k3&&(i+j)<=n;++j)
                pa[i]+=pa[i+j]*p[j],pb[i]+=pb[i+j]*p[j];
            pa[i]+=P,pb[i]+=1.0;
        }
        ans=pb[0]/(1-pa[0]);
        printf("%.15lf\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值