初步的转移想法是一种 n2 的
就是 O(n) 枚举位置再 O(n) 枚举断点转移的那种
发现单词的长度不超过 100,就可以暴力了
每个位置匹配一下就可以了
由于不会有重复单词,用 Trie 树来‘加速’匹配
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> #include <locale> using namespace std; const int MAXL = 300005, MAXS = 4005, mod = 20071027; struct Node { int nxt[26]; bool isend; }t[MAXS * 105]; char txt[MAXL], wrd[105]; int s, ptr, len, tot; int f[MAXL]; inline int newnode() { ++ptr; memset(t + ptr, 0, sizeof(Node)); return ptr; } inline void Insert(char *s) { register int LEN = strlen(s), cur = 0; for (int i = 0; i < LEN; ++i) { register int x = s[i] - 'a'; if (!t[cur].nxt[x]) t[cur].nxt[x] = newnode(); cur = t[cur].nxt[x]; } t[cur].isend = true; } inline void work(int pos) { register int cur = 0; for (int i = pos; i < len; ++i) { register int x = txt[i] - 'a'; if (!t[cur].nxt[x]) return; cur = t[cur].nxt[x]; if (t[cur].isend) f[pos] = (f[pos] + f[i + 1]) % mod; } } inline void clearall() { memset(f, 0, sizeof(f)); memset(t + 0, 0, sizeof(Node)); ptr = 0; return; } int main() { while (~scanf("%s", txt)) { clearall(); scanf("%d", &s); for (int i = 1; i <= s; ++i) { scanf("%s", wrd); Insert(wrd); } len = strlen(txt); f[len] = 1; for (int i = len - 1; i >= 0; --i) work(i); printf("Case %d: %d ", ++tot, f[0]); } return 0; }