[ZOJ3329]One Person Game 題解
阿新 • • 發佈:2022-05-10
期望 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\)
Solution
容易地,設 \(dp[i]\) 表示當前得分 \(i\) 到目標狀態的期望次數
容易 \(k^3\) 預處理出 \(p[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; }