做法:最简单AC自动机,又称Trie图... Trie图的分成两步来构造,第一步建立最普通的Trie树,第二步类似KMP的思想建立fail指针指向,使用BFS线扫所有节点即可完成. #include <stdio.h> #include <string.h> const int MAXZ = 26; //字符集大小 const int MAXN = 2000000; //最大节点数量 typedef struct _Node { _Node *next[MAXZ]; //trie树 _Node *fail; //失配指针 int k; //Node记录值,因题而异 //int out; //简化的out }Node; Node nw[MAXN], *q[MAXN]; int np; //申请新节点 Node * newNode() { memset(nw + np, 0, sizeof(nw[0])); return &nw[np++]; } //初始化root, 因为root的有一个自循环,特殊处理一下... Node * init_root() { np = 0; Node *root = newNode(); int i; for(i = 0; i < MAXZ; ++i) root->next[i] = root; return root; } void insert(Node *root, char *s) { Node *p = root; int i = 0, j = *s - 'a'; if(root->next[j] == root) root->next[j] = newNode(); while(*s) { j = *s - 'a'; if(p->next[j] == NULL) p->next[j] = newNode(); //i += p->out; p = p->next[j]; ++s; } ++(p->k); //标记这里为一个字符串终止,因题目而已 //p->out = i + 1; } void init_ac(Node * root) { int i, beg = 0, end = 0; Node *p, *f, *nt; root->fail = NULL; for(i = 0; i < MAXZ; ++i) { p = root->next[i]; if(p != root) { p->fail = root; q[end++] = p; } } while(beg < end) { p = q[beg++]; for(i = 0; i < MAXZ; ++i) { if((nt = p->next[i]) != NULL) { q[end++] = nt; f = p->fail; while(f->next[i] == NULL) f = f->fail; nt->fail = f->next[i]; //nt->out = nt->out + nt->fail->out; } } } } int query(Node *root, char *s) { Node *p = root, *f; int i, re = 0; while(*s) { i = *s - 'a'; while(p->next[i] == NULL) p = p->fail; p = p->next[i]; f = p; while(f != root && f->k != -1) { re += f->k; f->k = -1; f = f->fail; } ++s; } return re; } int main() { int n, m; char s[1000010]; Node *root; scanf("%d", &n); while(n--) { scanf("%d", &m); gets(s); root = init_root(); while(m--) { gets(s); insert(root, s); } init_ac(root); gets(s); printf("%d/n", query(root, s)); } return 0; }