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]的前缀}

posted @ 2016-11-09 11:37  kiraa  阅读(175)  评论(0编辑  收藏  举报