给出M个短串,这些短串由前N个大写字母组成。然后随机的按字符生成字符串,每次生成1~N个字符的概率是相等的,当生成串包含任意一个指定短串时,就停止生成。问生成串的长度的期望是多少。
首先建立Trie图,对每个可能作为短串结束的点都打上标记。用E(x)表示从这个点走到停止生成所需长度的期望。显然,对于打标记的点,E(x)=0。对于没打标记的点E(x)=∑(E(next[x][i])*1/N)+1(0<i<N),next[x][i]是它在trie图中接受字母i后走到的点。
然后根据Trie图建立方程组,用高斯消元求解E(0)即可。
高斯消元的精度着实很低,现在的代码能过G++,但C++还是WA。。。。估计还是什么地方精度有问题。。
1 #include <string.h> 2 #include <stdio.h> 3 #include <math.h> 4 #include <algorithm> 5 #define MAXN 105 6 const double eps=1e-12; 7 int cas,n,m; 8 char s[12]; 9 int next[MAXN][8],flag[MAXN],fail[MAXN],pos; 10 int newnode(){ 11 memset(next[pos],0,sizeof next[pos]); 12 flag[pos]=fail[pos]=0; 13 return pos++; 14 } 15 void insert(char *s){ 16 int p=0; 17 for(int i=0;s[i];i++){ 18 int &x=next[p][s[i]-'A']; 19 p=x?x:x=newnode(); 20 } 21 flag[p]=1; 22 } 23 int q[MAXN],front,rear; 24 void makenext(){ 25 q[front=rear=0]=0,rear++; 26 while(front<rear){ 27 int u=q[front++]; 28 for(int i=0;i<n;i++){ 29 int v=next[u][i]; 30 if(v==0)next[u][i]=next[fail[u]][i]; 31 else q[rear++]=v; 32 if(v&&u){ 33 fail[v]=next[fail[u]][i]; 34 flag[v]|=flag[fail[v]]; 35 } 36 } 37 } 38 } 39 int id[MAXN],w,h; 40 double mat[MAXN][MAXN],ans[MAXN]; 41 void makemat(){ 42 w=h=0; 43 memset(id,0,sizeof id); 44 memset(mat,0,sizeof mat); 45 for(int i=0;i<pos;i++) 46 if(flag[i]==0)id[i]=w++; 47 for(int u=0;u<pos;u++){ 48 if(flag[u]==0){ 49 mat[h][id[u]]=-n; 50 mat[h][w]=n; 51 for(int i=0;i<n;i++){ 52 int v=next[u][i]; 53 if(flag[v]==1)continue; 54 mat[h][id[v]]+=1.0; 55 } 56 h++; 57 } 58 } 59 w++; 60 } 61 double gauss(){ 62 makemat(); 63 int row=0,col=0; 64 for(;row<h&&col<w;col++){ 65 int maxr=row; 66 for(int i=row+1;i<h;i++) 67 if(fabs(mat[i][col])>fabs(mat[maxr][col]))maxr=i; 68 if(fabs(mat[maxr][col])<eps)continue; 69 if(maxr!=row)for(int i=0;i<w;i++)std::swap(mat[maxr][i],mat[row][i]); 70 for(int k1=row+1;k1<h;k1++){ 71 double div=mat[k1][col]/mat[row][col]; 72 for(int k2=col;k2<w;k2++){ 73 mat[k1][k2]-=div*mat[row][k2]; 74 } 75 } 76 row++; 77 } 78 memset(ans,0,sizeof ans); 79 for(int i=h-1;i>=0;i--){ 80 double tmp=0; 81 for(int j=i+1;j<w-1;j++){ 82 tmp+=ans[j]*mat[i][j]; 83 } 84 ans[i]=(mat[i][w-1]-tmp)/mat[i][i]; 85 } 86 return -ans[0]; 87 } 88 int main(){ 89 //freopen("test.in","r",stdin); 90 scanf("%d",&cas); 91 while(cas--){ 92 scanf("%d%d",&n,&m); 93 pos=0;newnode(); 94 for(int i=1;i<=m;i++){ 95 scanf("%s",s); 96 insert(s); 97 } 98 makenext(); 99 double res=gauss(); 100 printf("%.2f\n",res); 101 } 102 }