将K个模板串构成一个AC自动机,那些能匹配到的单词节点都称之为禁止节点。
然后问题就变成了在Tire树上走L步且不经过禁止节点的概率。
根据全概率公式用记忆化搜索求解。
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 const int maxnode = 500; 7 const int sigma_size = 64; 8 int idx[256]; 9 10 struct AhoCorasickAutomata 11 { 12 int ch[maxnode][sigma_size]; 13 int match[maxnode]; 14 int f[maxnode]; 15 int sz; 16 17 void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } 18 19 void insert(char* s) 20 { 21 int u = 0, n = strlen(s); 22 for(int i = 0; i < n; i++) 23 { 24 int c = idx[s[i]]; 25 if(!ch[u][c]) 26 { 27 memset(ch[sz], 0, sizeof(ch[sz])); 28 match[sz] = 0; 29 ch[u][c] = sz++; 30 } 31 u = ch[u][c]; 32 } 33 match[u] = 1; 34 } 35 36 void getFail() 37 { 38 queue<int> q; 39 f[0] = 0; 40 for(int c = 0; c < sigma_size; c++) 41 { 42 int u = ch[0][c]; 43 if(u) { f[u] = 0; q.push(u); } 44 } 45 while(!q.empty()) 46 { 47 int r = q.front(); q.pop(); 48 for(int c = 0; c < sigma_size; c++) 49 { 50 int u = ch[r][c]; 51 if(!u) { ch[r][c] = ch[f[r]][c]; continue; } 52 q.push(u); 53 int v = f[r]; 54 while(v && !ch[v][c]) v = f[v]; 55 f[u] = ch[v][c]; 56 match[u] |= match[f[u]]; 57 } 58 } 59 } 60 }ac; 61 62 int n; 63 const int maxl = 100 + 10; 64 char s[30][30]; 65 double prob[sigma_size]; 66 67 int vis[maxnode][maxl]; 68 double d[maxnode][maxl]; 69 70 double getProb(int u, int L) 71 { 72 if(L == 0) return 1.0; 73 if(vis[u][L]) return d[u][L]; 74 vis[u][L] = 1; 75 double& ans = d[u][L]; 76 ans = 0; 77 for(int c = 0; c < n; c++) 78 if(!ac.match[ac.ch[u][c]]) 79 ans += prob[c] * getProb(ac.ch[u][c], L-1); 80 return ans; 81 } 82 83 int main() 84 { 85 //freopen("in.txt", "r", stdin); 86 87 int T; 88 scanf("%d", &T); 89 for(int kase = 1; kase <= T; kase++) 90 { 91 int k, L; 92 scanf("%d", &k); 93 for(int i = 0; i < k; i++) scanf("%s", s[i]); 94 95 scanf("%d", &n); 96 for(int i = 0; i < n; i++) 97 { 98 char s1[9]; 99 scanf("%s%lf", s1, &prob[i]); 100 idx[s1[0]] = i; 101 } 102 103 ac.init(); 104 for(int i = 0; i < k; i++) ac.insert(s[i]); 105 ac.getFail(); 106 scanf("%d", &L); 107 memset(vis, 0, sizeof(vis)); 108 printf("Case #%d: %.6f\n", kase, getProb(0, L)); 109 } 110 111 return 0; 112 }