这题由于是一个单词,其实直接kmp+dp也无妨。建立自动机当然也是可以的。设dp[i][j]表示匹配到第i个字母的时候,在单词中处于第j个位置的概率,因此最终的答案是dp[0~m][len],m是输入的长度,len是单词的长度。转移方程见代码,即在一个节点的位置时,枚举下一步的走法,乘以这种走法的概率即是对下一个状态的概率贡献。
其实自动机的fail指针跳转的位置即是kmp中nxt数组跳转的位置。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 { 2 while(j && word[j+1] != word[i]) j = nxt[j]; 3 if(word[j+1] == word[i]) j++; 4 nxt[i] = j; 5 } 6 } 7 8 int main() 9 { 10 while(scanf("%d%d",&n,&m) == 2) 11 { 12 if(n==0 && m==0) break; 13 char s[5]; 14 for(int i=1;i<=n;i++) 15 { 16 scanf("%s%lf",s,p+i); 17 c[i] = s[0]; 18 } 19 scanf("%s",word+1); 20 len = strlen(word+1); 21 get_nxt(); 22 memset(dp,0,sizeof dp); 23 dp[0][0] = 1.0; 24 for(int i=0;i<m;i++) 25 { 26 for(int j=0;j<len;j++) 27 { 28 for(int k=1;k<=n;k++) 29 { 30 int pos = j; 31 while(pos && word[pos+1] != c[k]) pos = nxt[pos]; 32 if(word[pos+1] == c[k]) pos++; 33 dp[i+1][pos] += dp[i][j] * p[k]; 34 } 35 } 36 } 37 double ans = 0.0; 38 for(int i=0;i<=m;i++) ans += dp[i][len]; 39 printf("%.2f%%\n",ans*100.0); 40 } 41 return 0; 42 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int MAX_Tot = 100 + 50; 4 5 int n,m,len; 6 double p[30]; 7 char word[20]; 8 int nxt[20]; 9 double dp[1005][20]; 10 11 struct Aho 12 { 13 struct state 14 { 15 int nxt[26]; 16 int fail,cnt; 17 }stateTable[MAX_Tot]; 18 19 int size; 20 21 queue<int> que; 22 23 void init() 24 { 25 while(que.size()) que.pop(); 26 for(int i=0;i<MAX_Tot;i++) 27 { 28 memset(stateTable[i].nxt,0,sizeof(stateTable[i].nxt)); 29 stateTable[i].fail = stateTable[i].cnt = 0; 30 } 31 size = 1; 32 } 33 34 void insert(char *s) 35 { 36 int n = strlen(s); 37 int now = 0; 38 for(int i=0;i<n;i++) 39 { 40 char c = s[i]; 41 if(!stateTable[now].nxt[c-'a']) 42 stateTable[now].nxt[c-'a'] = size++; 43 now = stateTable[now].nxt[c-'a']; 44 } 45 stateTable[now].cnt++; 46 } 47 48 void build() 49 { 50 stateTable[0].fail = -1; 51 que.push(0); 52 53 while(que.size()) 54 { 55 int u = que.front();que.pop(); 56 for(int i=0;i<26;i++) 57 { 58 if(stateTable[u].nxt[i]) 59 { 60 if(u == 0) stateTable[stateTable[u].nxt[i]].fail = 0; 61 else 62 { 63 int v = stateTable[u].fail; 64 while(v != -1) 65 { 66 if(stateTable[v].nxt[i]) 67 { 68 stateTable[stateTable[u].nxt[i]].fail = stateTable[v].nxt[i]; 69 break; 70 } 71 v = stateTable[v].fail; 72 } 73 if(v == -1) stateTable[stateTable[u].nxt[i]].fail = 0; 74 } 75 que.push(stateTable[u].nxt[i]); 76 } 77 /*****建立自动机nxt指针*****/ 78 else 79 { 80 if(u == 0) stateTable[u].nxt[i] = 0; 81 else 82 { 83 int p = stateTable[u].fail; 84 while(p != -1 && stateTable[p].nxt[i] == 0) p = stateTable[p].fail; 85 if(p == -1) stateTable[u].nxt[i] = 0; 86 else stateTable[u].nxt[i] = stateTable[p].nxt[i]; 87 } 88 } 89 /*****建立自动机nxt指针*****/ 90 } 91 } 92 } 93 }aho; 94 95 int main() 96 { 97 while(scanf("%d%d",&n,&m) == 2) 98 { 99 if(n==0 && m==0) break; 100 aho.init(); 101 char s[5]; 102 memset(p,0,sizeof p); 103 for(int i=1;i<=n;i++) 104 { 105 double t; 106 scanf("%s%lf",s,&t); 107 p[s[0]-'a'] = t; 108 } 109 scanf("%s",word+1); 110 aho.insert(word+1); aho.build(); 111 memset(dp,0,sizeof dp); 112 dp[0][0] = 1.0; 113 int sz = aho.size-1; 114 for(int i=0;i<m;i++) 115 { 116 for(int j=0;j<sz;j++) 117 { 118 for(int k=0;k<26;k++) 119 { 120 int v = aho.stateTable[j].nxt[k]; 121 dp[i+1][v] += dp[i][j] * p[k]; 122 } 123 } 124 } 125 double ans = 0.0; 126 for(int i=0;i<=m;i++) ans += dp[i][sz]; 127 printf("%.2f%%\n",ans*100.0); 128 } 129 return 0; 130 }