Link
设扔出\(i\)的概率为\(P_i\)。
设\(f_{i,j}\)为首次出现的是\(s_i\)且随机序列长度为\(j\)的概率,其OGF为\(F_i(x)\)。
设\(g_i\)表示随机序列长度达到\(i\)且尚未结束的概率,其OGF为\(G(x)\)。
设\(a_{i,j,k}=[pre(s_i,k)=suf(s_j,k)],P(S)=\prod\limits_{x\in S}P_x\)。
那么我们有
\[\begin{aligned} \sum\limits_{i=1}^nF_i(x)+G(x)&=1+xG(x)\\ \forall i\in[1,n]\qquad G(x)P(s_i)x^{len_i}&=\sum\limits_{j=1}^n\sum\limits_{k=1}^{len_i}a_{i,j,k}F_j(x)P(s_i[k+1,len_i])x^{len_i-k} \end{aligned} \]
我们要求的是\(\sum\limits_{i=1}^nF_i'(1)\),将上述等式变形可以得到
\[\begin{aligned} \sum\limits_{i=1}^nF_i'(1)&=G(1)\\ \forall i\in[1,n]\qquad G(1)&=\sum\limits_{j=1}^nF_j(1)\sum\limits_{k=1}^{len_i}\frac{a_{i,j,k}}{P(pre(s_i,k))} \end{aligned} \]
同时我们还有\(\sum\limits_{i=1}^nF_i(1)=1\)。
然后利用Gauss消元法求解即可。
求\(\sum\limits_{k=1}^{len_i}\frac{a_{i,j,k}}{P(pre(s_i,k))}\)可以使用hash、KMP、AC自动机等方法。
#include<cmath>
#include<cstdio>
#include<algorithm>
using ld=long double;
const int N=307;
int n,m,next[N];char s[N][N];ld a[N][N];
int main()
{
scanf("%d%d",&n,&m),a[n][n+1]=1,next[0]=-1;
for(int i=0;i<n;++i) scanf("%s",s[i]);
for(int i=0;i<n;++i)
{
for(int j=0,k=-1;j<m;next[++j]=++k) while(~k&&s[i][j]!=s[i][k]) k=next[k];
for(int j=0;j<n;++j)
{
int k=0;
for(int l=0;l<m;++l,++k) while(~k&&s[j][l]!=s[i][k]) k=next[k];
for(;k;k=next[k]) a[i][j]+=pow((ld)0.5,m-k);
}
a[i][n]=-pow((ld)0.5,m),a[n][i]=1;
}
for(int i=0;i<=n;++i)
{
int p=i;
for(int j=i+1;j<=n;++j) if(fabs(a[j][i])>fabs(a[p][i])) p=j;
std::swap(a[i],a[p]);
for(int j=n+i;j>=i;--j) a[i][j]/=a[i][i];
for(int j=0;j<=n;++j) if(i!=j) for(int k=n+1;k>=i;--k) a[j][k]-=a[j][i]*a[i][k];
}
for(int i=0;i<n;++i) printf("%.12Lf\n",a[i][n+1]);
}