[ZOJ3329]One Person Game 题解

期望 DP+解系数 Trick

Statement

有三个色子,第 \(i\) 个色子有 \(k_i\) 面,每面面值为 \(1,2, … ,k_i\) ,每面出现的概率相同

每次扔出三个色子,将面值加入总得分中。

问期望扔多少次使得总得分大于 \(n\)

额外规定: 当 \(k1=a, k2 = b, k3 =c\) 时,总得分清零。

多组数据。

\(1 ≤ T≤ 300, 0 ≤n≤ 500,1 < k1,k2, k3 ≤ 6\)

ZOJ (pintia.cn)

Solution

容易地,设 \(dp[i]\) 表示当前得分 \(i\) 到目标状态的期望次数

容易 \(k^3\) 预处理出 \(p[k]\) 表示一次扔出得分 \(k\) 的概率

那么 \(dp[i]=\sum (dp[i+k]\times p[k])+dp[0]\times p[0]\)

发现每一个式子里面都有 \(dp[0]\) 而且答案就是 \(dp[0]\)

高消时间炸糊了,这里给出一个 nb 的 Trick:

考虑设 \(dp[i]=A[i]\times dp[0]+B[i]\)

那么 \(dp[i]=\sum p[k](A[i+k]\times dp[0]+B[i+k])+dp[0]\times p[0]+1\)

所以 \(dp[i]=(\sum (p[k]\times A[i+k])+p[0])dp[0]+\sum(p[k]\times B[i+k])+1\)

所以 \(A[i]=\sum (p[k]\times A[i+k])+p[0],B[i]=\sum(p[k]\times B[i+k])+1\)

你发现 \(A,B\) 的递推式没有后效性!所以就可以做了

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
const int inf = 2e9;

char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}

double a[1000],b[1000],p[100];
int T,n,k1,k2,k3,x,y,z;

signed main(){
    T=read();
    while(T--){
        memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(p,0,sizeof(p));
        n=read(),k1=read(),k2=read(),k3=read(),x=read(),y=read(),z=read();
        p[0]=1.0/(k1*k2*k3);
        for(int i=1;i<=k1;++i)for(int j=1;j<=k2;++j)
            for(int k=1;k<=k3;++k)if(!(i==x&&j==y&&k==z))
                p[i+j+k]+=p[0];
        for(int i=n;~i;--i){
            a[i]=p[0],b[i]=1;
            for(int k=3;k<=k1+k2+k3;++k)
                a[i]+=p[k]*a[i+k],b[i]+=p[k]*b[i+k];
        }
        printf("%.15lf\n",b[0]/(1.0-a[0]));
    }
    return 0;
}
posted @ 2022-05-10 18:19  _Famiglistimo  阅读(28)  评论(0编辑  收藏  举报