CF618G Combining Slimes

输出是浮点数,发现合成到 (50) 以上的数字的概率已经很小了,可以忽略。

(a_{i,j},b_{i,j}) 表示用长度为 (i) 的格子合成数字 (j) 的概率,其中 (b_{i,j}) 表示第一个数字必须为 (2),得 (a_{i,j}=a_{i,j-1} imes a_{i-1,j-1},b_{i,j}=b_{i,j-1} imes a_{i-1,j-1})。不难发现当 (i>j) 时有 (a_{i+1,j}=a_{i,j},b_{i+1,j}=b_{i,j})

({a}'_{i,j},{b}'_{i,j}) 表示最终序列倒数第 (i) 个格子合成数字 (j) 的概率,得 ({a}'_{i,j}=a_{i,j}(1-a_{i-1,j}),{b}'_{i,j}=b_{i,j}(1-a_{i-1,j}))

考虑 (DP),设 (f_{i,j}) 表示当最终序列倒数第 (i) 个格子为 (j) 时,倒数 (i) 个数字和的期望,得:

[large f_{i,j}= egin{cases} frac{1}{sumlimits_{k=1}^{j-1}{a}'_{i-1,k}}left(sumlimits_{k=1}^{j-1}f_{i-1,k} imes {a}'_{i-1,k} ight)+j &j eq 1 \ frac{1}{sumlimits_{k=2}^{50}{b}'_{i-1,k}}left(sumlimits_{k=2}^{50}f_{i-1,k} imes {b}'_{i-1,k} ight)+j &j=1 end{cases} ]

预处理前 (50) 项后矩阵快速幂即可。

#include<bits/stdc++.h>
#define maxn 60
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,lim=50;
double p,ans,s;
double a[maxn][maxn],b[maxn][maxn],f[maxn][maxn];
struct matrix
{
    double a[maxn][maxn];
}m,v;
matrix operator * (const matrix &x,const matrix &y)
{
    matrix z;
    memset(z.a,0,sizeof(z.a));
    for(int k=0;k<=lim;++k)
        for(int i=0;i<=lim;++i)
            for(int j=0;j<=lim;++j)
                z.a[i][j]+=x.a[i][k]*y.a[k][j];
    return z;
}
int main()
{
    read(n),scanf("%lf",&p),p/=(double)1000000000;
    for(int i=1;i<=lim;++i) a[i][1]=p,a[i][2]=b[i][2]=1-p;
    for(int i=2;i<=lim;++i)
        for(int j=2;j<=lim;++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=lim;i;--i)
        for(int j=1;j<=lim;++j)
            a[i][j]*=1-a[i-1][j],b[i][j]*=1-a[i-1][j];
    f[1][1]=1,f[1][2]=2;
    for(int i=2;i<=lim;++i)
    {
        for(int j=2;j<=lim;++j)
        {
            s=0;
            for(int k=1;k<j;++k) f[i][j]+=f[i-1][k]*a[i-1][k],s+=a[i-1][k];
            f[i][j]=f[i][j]/s+j;
        }
        s=0;
        for(int k=2;k<=lim;++k) f[i][1]+=f[i-1][k]*b[i-1][k],s+=b[i-1][k];
        f[i][1]=f[i][1]/s+1;
    }
    if(n<=lim)
    {
        for(int i=1;i<=n+1;++i) ans+=f[n][i]*a[n][i];
        printf("%.15lf",ans);
        return 0;        
    }
    v.a[0][0]=m.a[0][0]=1;
    for(int i=1;i<=lim;++i) v.a[0][i]=f[lim][i],m.a[0][i]=i;
    for(int i=2;i<=lim;++i)
    {
        s=0;
        for(int j=1;j<i;++j) m.a[j][i]+=a[lim][j],s+=a[lim][j];
        for(int j=1;j<i;++j) m.a[j][i]/=s;
    }
    s=0;
    for(int j=2;j<=lim;++j) m.a[j][1]+=b[lim][j],s+=b[lim][j];
    for(int j=2;j<=lim;++j) m.a[j][1]/=s;
    n-=lim;
    while(n)
    {
        if(n&1) v=v*m;
        m=m*m,n>>=1;
    }
    for(int i=1;i<=lim;++i) ans+=v.a[0][i]*a[lim][i];
    printf("%.15lf",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/14451388.html