LA 3942 ——Trie (前缀树)、DP
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int M = 20071027; 8 const int maxn = 300000 + 10; 9 const int maxnode = 400000+10; 10 const int _size = 26; 11 12 struct Trie { 13 int ch[maxnode][_size]; 14 int val[maxnode]; 15 int sz; 16 Trie() { 17 sz = 1; 18 memset(ch[0], 0, sizeof (ch[0])); 19 } 20 int idx(int c) {return c - 'a';} 21 22 void insert(char *s, int v) { //插入字符串s和权值v 23 int u = 0, n = strlen(s); 24 for(int i = 0; i < n; i++) { 25 int c = idx(s[i]); 26 if(!ch[u][c]) { 27 memset(ch[sz], 0, sizeof (ch[sz])); 28 val[sz] = 0; 29 ch[u][c] = sz++; 30 } 31 u = ch[u][c]; 32 } 33 val[u] = v; 34 } 35 void find_prefixes(const char *s, int len, vector<int>& ans) { //寻找字符串s的前缀 36 int u = 0; 37 for(int i = 0; i < len; i++) { 38 if(s[i] == '\0') break; 39 int c = idx(s[i]); 40 if(!ch[u][c]) break; 41 u = ch[u][c]; 42 if(val[u] != 0) ans.push_back(val[u]); 43 } 44 } 45 46 void clear() { 47 sz = 1; 48 memset(val, 0 , sizeof val); 49 memset(ch[0], 0, sizeof (ch[0])); 50 } 51 }; 52 53 Trie T; 54 char S[maxn], s[110]; 55 int d[maxn]; 56 57 int cal_d() { 58 int L = strlen(S); 59 d[L] = 1; 60 for(int i = L-1; i >= 0; i--){ 61 vector<int> p; 62 T.find_prefixes(S+i, L-i, p); 63 for(int j = 0; j < p.size(); j++) { 64 d[i] = (d[i] + d[i + p[j]]) % M; 65 } 66 } 67 return d[0]; 68 } 69 int main(int argc, const char * argv[]) { 70 int tt = 0; 71 while(scanf("%s", S) == 1){ 72 T.clear(); 73 memset(d, 0, sizeof d); 74 int m; 75 scanf("%d", &m); 76 for(int i = 0; i < m; i++) { 77 scanf("%s", s); 78 T.insert(s, strlen(s)); 79 } 80 int ans = cal_d(); 81 printf("Case %d: %d\n", ++tt, ans); 82 } 83 return 0; 84 }
解题思路:
令d(i)表示从字符i开始的字符串(即S[i...L])的分解方案数。
则状态转移方程:
d(i) = sum{d(i+len(x)) | x为S[i..L]的前缀}