题目描述:
题目分析:
先不考虑格子长度的限制,我们要得到数字 的概率 ,而 ,那么 ,当 时已经无限趋于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);
}