假设匹配到一个串后不会停止。
设
pi
p
i
表示匹配到的第一个串为
i
i
的概率, 表示没有匹配到任何串的概率。显然
pi
p
i
就是答案。
对于第
i
i
个串,我们考虑由一个没匹配到任何串的字符串接上它形成的串。
显然出现的概率为 。
再考虑用另一种方法表示它。
当
i
i
是第一个匹配到的时候,概率为 。
当
i
i
不是第一个匹配到的时候,假设第一个匹配到的串为 。由于原串没有匹配到任何串,所以
i
i
的一部分前缀一定与 的一部分后缀重合。假设重合的长度为
k
k
,此时概率为 ,表示在
j
j
的基础上加上 个字符形成
i
i
。
所以对于每个 ,我们可以得到一个方程:
再加上方程 ∑pi=1 ∑ p i = 1 ,我们就有 n+1 n + 1 个方程和 n+1 n + 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;
}