网址:https://vjudge.net/problem/HDU-2222
题意:
统计模式串在文本串的出现次数,文本串只含有小写字母。
题解:
$AC$自动机的模板题,在$Trie$树上建出$Trie$图,然后查询的时候跳$fail$指针直到已访问结点或者根结点记录数量,标记已访问结点即可。
AC代码:
#include <cstring> #include <cstdio> #include <queue> using namespace std; #define maxn int(5e5+9) #define m(a,b) memset (a,b,sizeof(a)); #pragma GCC Optimize(2) int trie[maxn][26]; int cntword[maxn]; int fail[maxn]; int cnt = 0,ans=0; struct AC { void insert(char *str) { int root = 0, next; int len=strlen(str); for (int i = 0; i < len; ++i) { next = str[i] - 'a'; if (!trie[root][next]) trie[root][next] = ++cnt; root = trie[root][next]; } ++cntword[root]; } void buildfail() { queue<int>que; for (int i = 0; i < 26; ++i) if (trie[0][i]) { que.push(trie[0][i]); fail[trie[0][i]] = 0; } while (!que.empty()) { int now = que.front(); que.pop(); for (int i = 0; i < 26; ++i) { if (trie[now][i]) { fail[trie[now][i]] = trie[fail[now]][i]; que.push(trie[now][i]); } else trie[now][i] = trie[fail[now]][i]; } } } void query(char *str) { int now = 0; int len=strlen(str); for (int i = 0; i < len; ++i) { now = trie[now][str[i] - 'a']; for (int j = now; j&&cntword[j]!=-1 ; j = fail[j]) { ans+=cntword[j]; cntword[j]=-1; } } } }; char mod[55],word[1000005]; int main() { int n,m; AC ac; scanf("%d",&n); while(n--) { m(trie,0); m(fail,0); m(cntword,0); ans=0; scanf("%d",&m); for(int i=0;i<m;++i) { scanf("%s",mod); ac.insert(mod); } ac.buildfail(); scanf("%s",word); ac.query(word); printf("%d\n",ans); } return 0; }