题目链接:【http://acm.hdu.edu.cn/showproblem.php?pid=2222】
题意:给出很多小字符串,然后给出一个文本串,问文本串中包含多少个小字符串。也就是说如果文本串中出现了多次某个小字符串,则只算一次。
题解:裸的AC自动机,首先利用小字符串建立一个Trie,然后再Trie上做KMP,使得为一个节点具有一个fail指针,其含义是,当文本串在某个节点失配时,则在Trie上找到根节点到这个节点的最长后缀的一个串,然后指向它。
不断地匹配下去就行了。
#include<bits/stdc++.h> using namespace std; const int maxn = 5e5 + 10; struct Aho_C { int next[maxn][26], fail[maxn], End[maxn]; int root, L; int newnode() { for(int i = 0; i < 26; i++) next[L][i] = -1; End[L++] = 0; return L - 1; } void init() { L = 0; root = newnode(); } void Insert(char buf[]) { int len = strlen(buf); int now = root; for(int i = 0; i < len; i++) { if(next[now][buf[i] - ‘a‘] == -1) next[now][buf[i] - ‘a‘] = newnode(); now = next[now][buf[i] - ‘a‘]; } End[now]++; } void Build() { queue<int>Q; fail[root] = root; for(int i = 0; i < 26; i++) if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } while( !Q.empty() ) { int now = Q.front(); Q.pop(); for(int i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } int Query(char buf[]) { int len = strlen(buf); int now = root, res = 0; for(int i = 0; i < len; i++) { now = next[now][buf[i] - ‘a‘]; int temp = now; while( temp != root ) { res += End[temp]; End[temp] = 0; temp = fail[temp]; } } return res; } }ac; char buf[maxn * 2]; int main() { int T, n; scanf("%d", &T); while( T-- ) { scanf("%d", &n); ac.init(); for(int i = 0; i < n; i++) { scanf("%s", buf); ac.Insert(buf); } ac.Build(); scanf("%s", buf); printf("%d\n", ac.Query(buf)); } return 0; }
时间: 2024-10-31 06:46:52