分析:
如果数据范围再小点,可以利用BZOJ1444有趣的游戏方法来做。
所以这里为了优化,直接存储下来从某个字符串转移到另一个的概率即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 310
using namespace std;
long double pw[MAXN],tot[MAXN],a[MAXN][MAXN];
char s1[MAXN][MAXN];
int nxt[MAXN];
int n,m;
void build(char *s){
tot[0]=pw[m-1];
nxt[0]=-1;
for(int i=1;i<m;i++){
int las=nxt[i-1];
while(las!=-1&&s[las+1]!=s[i])
las=nxt[las];
if(s[las+1]==s[i]){
nxt[i]=las+1;
tot[i]=tot[las+1]+pw[m-i-1];
}
else{
nxt[i]=-1;
tot[i]=pw[m-i-1];
}
}
/*for(int i=0;i<m;i++) PF("[%lf]",tot[i]); PF("\n");*/
}
long double calc(int i,int j){
int now=-1;
for(int k=0;k<m;k++){
while(now!=-1&&s1[i][now+1]!=s1[j][k])
now=nxt[now];
if(s1[i][now+1]==s1[j][k])
now++;
}
if(now!=-1)
return tot[now];
return 0;
}
void gauss(int row,int col){
int r=0,c=0;
for(;r<row&&c<col-1;r++,c++){
int maxr=r;
for(int i=r+1;i<row;i++)
if(a[i][c]>a[maxr][c])
maxr=i;
swap(a[r],a[maxr]);
for(int i=0;i<row;i++)
if(i!=r){
double t=a[i][c]/a[r][c];
for(int j=c;j<col;j++)
a[i][j]=a[i][j]-t*a[r][j];
}
}
/*for(int i=0;i<row;i++){ for(int j=0;j<col;j++) PF("%lf ",a[i][j]); PF("\n"); }*/
}
int main(){
SF("%d%d",&n,&m);
pw[0]=1;
for(int i=1;i<=m;i++)
pw[i]=pw[i-1]*0.5;
for(int i=0;i<n;i++)
SF("%s",s1[i]);
for(int i=0;i<n;i++){
build(s1[i]);
for(int j=0;j<n;j++)
a[i][j]=calc(i,j);
}
for(int i=0;i<n;i++)
a[i][n]=-pw[m];
for(int i=0;i<n;i++)
a[n][i]=1;
a[n][n+1]=1;
gauss(n+2,n+2);
for(int i=0;i<n;i++)
PF("%.10Lf\n",a[i][n+1]/a[i][i]);
}
/* 3 3 THT TTH HTT */