硬币游戏
/* KMP+高斯消元 设N为未结束状态的概率。 假设用两个串TTH和HTT,设第一个获胜的概率是A,第二个人获胜的概率为B。 如果在N后面加上TTH,那么有三种可能。 NTTH=A+BTH+BH ,是什么意思呢?就是如果在N后面加入TTH,那么第一个人猜的序列出现在了硬币序列中,第一个人获胜,但是N是什么我们不清楚,但是有可能到达第一个T或者第二个T的时候第二个人就获胜了。 所以对于状态NTTH,可以由三个状态得到。 0.125N=A+0.25B+0.5B,0.5是正反面的概率。 上述式子可以用kmp球的,然后高斯消元求解。 */ #include<iostream> #include<cstdio> #define N 1010 using namespace std; char s[N][N]; double ec[N],a[N][N]; int va[N],vb[N],n,m; void init(){ ec[m]=1.0; for(int i=m-1;i;i--) ec[i]=ec[i+1]*0.5; for(int i=1;i<=n;i++){ va[1]=0; for(int k=2,p=0;k<=m;k++){ while(p&&s[i][k]!=s[i][p+1]) p=va[p]; if(s[i][k]==s[i][p+1]) p++; va[k]=p; } for(int j=1;j<=n;j++){ vb[0]=0; for(int k=1,p=0;k<=m;k++){ while(p&&s[j][k]!=s[i][p+1]) p=va[p]; if(s[j][k]==s[i][p+1]) p++; vb[k]=p; } for(int now=vb[m];now;now=va[now]) a[i][j]+=ec[now]; } a[i][n+1]=1; } } void gauss(){ for(int i=1;i<=n;i++){ for(int j=i+1;j<=n+1;j++) a[i][j]/=a[i][i]; a[i][i]=1; for(int j=i+1;j<=n;j++) for(int k=i+1;k<=n+1;k++) a[j][k]-=a[i][k]*a[j][i]; } for(int i=n;i;i--) for(int j=i+1;j<=n;j++) a[i][n+1]-=a[i][j]*a[j][n+1]; double sum=0,ans=0; for(int i=1;i<=n;i++) sum+=a[i][n+1]; for(int i=1;i<=n;i++){ ans=a[i][n+1];ans/=sum; printf("%.10f\n",(double)ans); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); init();gauss(); return 0; }