Accepted | 2222 | 593MS | 30816K | 2430 B | G++ |
第一道 AC 自动机,理解了就好写;
需要注意字典可能重复,重复的不能按一次算。
# include <cstdio> # include <cstring> # include <queue> using namespace std; # define WORD_LEN 50 + 5 # define MAXN 10000 + 5 # define ALPHA_SIZE 26 int n, id; char t[1000000 + 10]; char w[MAXN][WORD_LEN]; struct node { node * fail; node * next[ALPHA_SIZE]; int id; int isEnd; // 字典里有重复的单词 node () { fail = NULL; memset(next, 0, sizeof(next)); id = 0; isEnd = 0; } }* root; int alpha_map(char ch) { return ch - 'a'; } void insert_trie(node * root, char *s) { int c, i; node * p = root; for (i = 0; s[i]; ++i) { c = alpha_map(s[i]); if (NULL == p->next[c]) p->next[c] = new node; p = p->next[c]; } ++(p->isEnd); } void build_trie(node * root) { for (int i = 0; i < n; ++i) insert_trie(root, w[i]); } void build_AC_auto(node *root) { int i; node *cur, *tmp; queue <node *> Q; // 根节点的子节点单独处理 Q.push(root); for (i = 0; i < ALPHA_SIZE; ++i) { if (root->next[i]) { root->next[i]->fail = root; Q.push(root->next[i]); } }Q.pop(); // 根节点出队 // 更新非根节点子节点的 fail while (!Q.empty()) { cur = Q.front(); Q.pop(); // 当前节点出队 for (i = 0; i < ALPHA_SIZE; ++i) { if (cur->next[i]) { tmp = cur->fail; // 找到当前节点的 fail // 更新子节点的 fail while (tmp) { if (tmp->next[i]) { cur->next[i]->fail = tmp->next[i]; break; } tmp = tmp->fail; } // 没有找到可以匹配的 if (NULL == tmp) { cur->next[i]->fail = root; } // 将子节点入队 Q.push(cur->next[i]); } } } } int search(char *t, node * root) { int i, c, ret = 0; node *tmp, *p = root; for (i = 0; t[i]; ++i) { c = alpha_map(t[i]); while (root != p && NULL == p->next[c]) p = p->fail; p = p->next[c]; if (NULL == p) p = root; tmp = p; while (tmp) { if (tmp->isEnd) { ret += tmp->isEnd; tmp->isEnd = 0; } tmp = tmp->fail; } } return ret; } void init(void) { id = 0; scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%s", w[i]); scanf("%s", t); } void solve(void) { root = new node; build_trie(root); build_AC_auto(root); printf("%d\n", search(t, root)); } int main() { int T; scanf("%d", &T); while (T--) { init(); solve(); } return 0; }
/**/