CF618G Combining Slimes【條件概率DP】

題目描述:

洛谷 link
在這裏插入圖片描述
109<p110^{-9}<p\le 1

題目分析:

先不考慮格子長度的限制,我們要得到數字 xx 的概率 p[x]=p[x1]2p[x]=p[x-1]^2,而 p[2]max=1109p[2]_{max}=1-10^{-9},那麼 p[x]max=(1109)2x1p[x]_{max}=(1-10^{-9})^{2^{x-1}},當 x=50x=50 時已經無限趨於0,可以近似認爲不可能得到大於 50 的數。

a[i][j]a[i][j] 表示用 ii 個格子得到第一個數爲 jj 的概率,有:
{j>2, a[i][j]=a[i][j1]a[i1][j1]a[1][1]=p, a[1][2]=1pi>1, a[i][1]=1, a[i][2]=1p+p2\begin{cases} j>2, ~a[i][j]=a[i][j-1]*a[i-1][j-1]\\ a[1][1]=p,~a[1][2]=1-p\\ i>1,~a[i][1]=1,~a[i][2]=1-p+p^2\end{cases}

如果相鄰兩個格子爲1 21~2,那麼就不會往左合併了,可能會用到第一個產生的數爲 2 形成 jj 的概率。
b[i][j]b[i][j] 表示用 ii 個格子,第一次生成的數爲2,得到數 jj 的概率,有:
{j>2, b[i][j]=b[i][j1]a[i1][j1]b[i][2]=1p\begin{cases}j>2,~b[i][j]=b[i][j-1]*a[i-1][j-1]\\ b[i][2]=1-p\end{cases}

可以發現當 i>ji>j 時,a[i+1][j]=a[i][j], b[i+1][j]=b[i][j]a[i+1][j]=a[i][j],~b[i+1][j]=b[i][j]


dp[i][j]dp[i][j] 表示在最終序列中從後往前數第 ii 個數爲 jj 的前提下,後 ii 個數的期望大小和。

對於j>1j>1,轉移時要枚舉第 i1i-1 個數爲 k<jk<j,考慮在最終序列中第 ii 個數爲 jj 的前提下,第 i1i-1 個數爲 kk 的概率,不難發現它等於 a[i1][k](1a[i1][k])s=1j1a[i1][s](1a[i1][s])\frac {a[i-1][k]*(1-a[i-1][k])}{\sum_{s=1}^{j-1}a[i-1][s]*(1-a[i-1][s])}
因爲是在最終序列中,所以必須要保證“穩定”,因此記 A[i][j]=a[i][j](1a[i1][j])A[i][j]=a[i][j]*(1-a[i-1][j]) 表示第 ii 個數爲 jj 且第 i1i-1 個數 <j<j 的概率。(特別的,A[2][1]A[2][1] 的第二個數是可以爲 2 的,因此不等於0)

所以對於 j>1j>1,有:
dp[i][j]=j+k=1j1dp[i1][k]A[i1][k]s=1j1A[i1][s]dp[i][j]=j+\sum_{k=1}^{j-1}dp[i-1][k]*\frac {A[i-1][k]}{\sum_{s=1}^{j-1}A[i-1][s]}

而當 j=1j=1 時,要枚舉第 i1i-1 個數爲 k>1k>1,第一個生成的數必須是2,同理爲 kk 的概率爲 b[i1][k](1a[i1][k])s=250b[i1][s](a[i1][s])\frac {b[i-1][k]*(1-a[i-1][k])}{\sum_{s=2}^{50}b[i-1][s]*(a[i-1][s])},記 B[i][j]=b[i][j](1a[i1][j])B[i][j]=b[i][j]*(1-a[i-1][j]),則有:
dp[i][1]=1+k=250dp[i1][k]B[i1][k]s=250B[i1][s]dp[i][1]=1+\sum_{k=2}^{50}dp[i-1][k]*\frac {B[i-1][k]}{\sum_{s=2}^{50}B[i-1][s]}

i>ji>jA,BA,B 不會隨 ii 改變,所以先暴力算出 dp[51][...]dp[51][...] (實際上dp[50]也沒問題)後用 51*51 的矩陣加速DP就可以了。

最後 Ans=j=150A[n][j]dp[n][j]Ans=\sum_{j=1}^{50}A[n][j]*dp[n][j]

Code:

#include<bits/stdc++.h>
#define maxn 55
using namespace std;
const int N = 50;
int n;
double p,a[maxn][maxn],b[maxn][maxn],A[maxn][maxn],B[maxn][maxn],f[maxn][maxn],ans;
struct Mat{
	double s[maxn][maxn];
	Mat(){memset(s,0,sizeof s);}
	double* operator [] (int i){return s[i];}//awesome!
	Mat operator * (const Mat &B)const{
		Mat ret;
		for(int k=0;k<=N;k++) for(int i=0;i<=N;i++) if(s[i][k]) for(int j=0;j<=N;j++)
			ret.s[i][j]+=s[i][k]*B.s[k][j];
		return ret;
	}
}F,G;
int main()
{
	scanf("%d%lf",&n,&p),p/=1e9;
	a[1][1]=p,a[1][2]=b[1][2]=1-p;
	for(int i=2;i<=N;i++){
		a[i][1]=p,a[i][2]=1-p+p*p,b[i][2]=1-p;
		for(int j=3;j<=i+1;j++) a[i][j]=a[i][j-1]*a[i-1][j-1],b[i][j]=b[i][j-1]*a[i-1][j-1];
	}
	for(int i=1;i<=N;i++) for(int j=1;j<=i+1;j++) A[i][j]=a[i][j]*(1-a[i-1][j]),B[i][j]=b[i][j]*(1-a[i-1][j]);
	for(int i=1;i<=N;i++) f[1][i]=i;
	for(int i=2;i<=N;i++){
		double s=0;
		for(int j=2;j<=N;j++) f[i][1]+=f[i-1][j]*B[i-1][j],s+=B[i-1][j];
		f[i][1]=f[i][1]/s+1;
		double x=0,y=0;
		for(int j=2;j<=N;j++) x+=f[i-1][j-1]*A[i-1][j-1],y+=A[i-1][j-1],f[i][j]=j+x/y;
	}
	if(n<=N){
		for(int j=1;j<=N;j++) ans+=A[n][j]*f[n][j];
		return printf("%.8f\n",ans),0;
	}
	F[0][0]=G[0][0]=1;
	for(int i=1;i<=N;i++) G[0][i]=i,F[0][i]=f[N][i];
	double s=0;
	for(int i=2;i<=N;i++) s+=B[N][i];
	for(int k=2;k<=N;k++) G[k][1]=B[N][k]/s;
	s=0;
	for(int j=2;j<=N;j++){
		s+=A[N][j-1];
		for(int k=1;k<j;k++) G[k][j]=A[N][k]/s;
	}
	n-=N;
	for(;n;n>>=1,G=G*G) if(n&1) F=F*G;
	for(int j=1;j<=N;j++) ans+=A[N][j]*F[0][j];
	printf("%.8f\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章