題目描述:
題目分析:
先不考慮格子長度的限制,我們要得到數字 的概率 ,而 ,那麼 ,當 時已經無限趨於0,可以近似認爲不可能得到大於 50 的數。
設 表示用 個格子得到第一個數爲 的概率,有:
如果相鄰兩個格子爲,那麼就不會往左合併了,可能會用到第一個產生的數爲 2 形成 的概率。
設 表示用 個格子,第一次生成的數爲2,得到數 的概率,有:
可以發現當 時,
設 表示在最終序列中從後往前數第 個數爲 的前提下,後 個數的期望大小和。
對於,轉移時要枚舉第 個數爲 ,考慮在最終序列中第 個數爲 的前提下,第 個數爲 的概率,不難發現它等於
因爲是在最終序列中,所以必須要保證“穩定”,因此記 表示第 個數爲 且第 個數 的概率。(特別的, 的第二個數是可以爲 2 的,因此不等於0)
所以對於 ,有:
而當 時,要枚舉第 個數爲 ,第一個生成的數必須是2,同理爲 的概率爲 ,記 ,則有:
當 時 不會隨 改變,所以先暴力算出 (實際上dp[50]也沒問題)後用 51*51 的矩陣加速DP就可以了。
最後
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);
}