建立AC自动机,并求出转移矩阵。
再用$sum E(终止节点)=1$去替换第一个方程,高斯消元即可。
时间复杂度$O(n^3l^3)$。
注意精度问题,要特判0.00的情况。
#include<cstdio> #include<cmath> #include<algorithm> #define N 110 using namespace std; int n,l,S,i,j,k,tot,son[N][10],v[N],fail[N],q[N],fin[N]; char s[N];double t,p[N],a[N][N],ans[N]; int ins(){ scanf("%s",s); for(int x=0,i=0,w;i<l;i++){ if(!son[x][w=s[i]-'A'])son[x][w]=++tot;x=son[x][w]; if(i==l-1)return v[x]=1,x; } } void make(){ int h=1,t=0,i,j,x;fail[0]=-1; for(i=0;i<S;i++)if(son[0][i])q[++t]=son[0][i]; while(h<=t)for(x=q[h++],i=0;i<S;i++)if(son[x][i])fail[q[++t]=son[x][i]]=son[fail[x]][i];else son[x][i]=son[fail[x]][i]; } int main(){ scanf("%d%d%d",&n,&l,&S); for(i=0;i<S;i++)scanf("%lf%lf",&p[i],&t),p[i]/=t; for(i=0;i<n;i++)fin[i]=ins(); make(); for(i=0;i<=tot;i++)a[i+1][i+1]=-1; for(i=0;i<=tot;i++)if(!v[i])for(j=0;j<S;j++)a[son[i][j]+1][i+1]+=p[j]; for(a[1][tot+2]=1,i=0;i<=tot;i++)if(v[i])a[1][i+1]=1;else a[1][i+1]=0; for(tot++,i=1;i<=tot;i++){ for(k=i,j=i+1;j<=tot;j++)if(fabs(a[j][i])>fabs(a[k][i]))k=j; if(k!=i)for(j=i;j<=tot+1;j++)swap(a[i][j],a[k][j]); for(j=i+1;j<=tot;j++)for(t=a[j][i]/a[i][i],k=i;k<=tot+1;k++)a[j][k]-=a[i][k]*t; } for(ans[tot]=a[tot][tot+1]/a[tot][tot],i=tot-1;i;i--){ for(ans[i]=a[i][tot+1],j=tot;j>i;j--)ans[i]-=ans[j]*a[i][j]; ans[i]/=a[i][i]; } for(i=0;i<n;i++)if(ans[fin[i]+1]>0)printf("%.2f ",ans[fin[i]+1]);else puts("0.00"); return 0; }