假设匹配到一个串后不会停止。
设 pipi 表示匹配到的第一个串为 ii 的概率, 表示没有匹配到任何串的概率。显然 pipi 就是答案。
对于第 ii 个串,我们考虑由一个没匹配到任何串的字符串接上它形成的串。
显然出现的概率为 。
再考虑用另一种方法表示它。
当 ii 是第一个匹配到的时候,概率为 。
当 ii 不是第一个匹配到的时候,假设第一个匹配到的串为 。由于原串没有匹配到任何串,所以 ii 的一部分前缀一定与 的一部分后缀重合。假设重合的长度为 kk ,此时概率为 ,表示在 jj 的基础上加上 个字符形成 ii 。
所以对于每个 ,我们可以得到一个方程:
px⋅12m=pi+∑pj⋅12m−kpx·12m=pi+∑pj·12m−k
再加上方程 ∑pi=1∑pi=1 ,我们就有 n+1n+1 个方程和 n+1n+1 个未知数,高斯消元求解即可。
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef unsigned long long ull;
const int N=310;
const int H=7;
const db Eps=1e-7;
int k,n,m;
char s[N][N];
ull h[N][N],P[N];
db a[N][N],p[N];
void Guass() {
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;
if(p!=i) swap(a[p],a[i]);
db t=a[i][i];
for(int j=i;j<=n+1;j++) a[i][j]/=t;
for(int j=0;j<=n;j++)
if(i!=j&&fabs(a[j][i])>0) {
db t=a[j][i];
for(int k=0;k<=n+1;k++) a[j][k]-=t*a[i][k];
}
}
}
ull Get(int id,int l,int r) {
return h[id][r]-h[id][l-1]*P[r-l+1];
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%s",s[i]);
for(int j=0;j<m;j++) h[i][j]=h[i][j-1]*H+(s[i][j]=='T');
}
p[0]=P[0]=1;
for(int i=1;i<=m;i++) p[i]=p[i-1]/2,P[i]=P[i-1]*H;
a[0][n+1]=1;
for(int i=1;i<=n;i++) {
a[0][i]=1;a[i][0]=-p[m];
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++)
if(Get(i,0,k-1)==Get(j,m-k,m-1)) a[i][j]+=p[m-k];
}
Guass();
for(int i=1;i<=n;i++) printf("%.7lf\n",a[i][n+1]);
return 0;
}