题目描述:
给出n个模板串,然后给一个长串,问模板串在长串中出现了多少个。
大致思路:
应该是一个典型的模板题,用AC自动机就可以搞定。
但是,鉴于最近学了字符串哈希,那么就有了一个哈希的想法。首先计算每个模板串的哈希值,存到一个哈希表中,然后枚举每一个模板串的长度,把长串该长度的所有子串哈希值计算出来,判断是否出现在哈希表中,如果出现的话就把答案加一。但是字符串哈希之后实在是不会怎么用hashmap优化,所以只写出了用AC自动机的做法……当然,AC自动机还是很局限的,因为Trie不可能构造的过大,所以对于字符串匹配来说还是没法满足大多数需求的。
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 510000;
struct Trie {
int ch[M][26],fail[M],end[M],cnt,root;
int NewNode() {
++cnt;
memset(ch[cnt],-1,sizeof(ch[cnt]));
end[cnt] = 0;
fail[cnt] = -1;
return cnt;
}
void init() {
cnt = 0; root = NewNode();
}
void insert(char s[]) {
int len = strlen(s), pos = root;
for (int i = 0; i<len; i++) {
int val = s[i]-'a';
if (ch[pos][val] == -1) ch[pos][val] = NewNode();
pos = ch[pos][val];
}
end[pos]++;
}
queue<int> Q;
void get_fail() {
fail[root] = root;
for (int i = 0; i<26; i++)
if (ch[root][i] == -1) ch[root][i] = root;
else {
fail[ch[root][i]] = root;
Q.push(ch[root][i]);
}
while (!Q.empty()) {
int pos = Q.front(); Q.pop();
for (int i = 0; i<26; i++)
if (ch[pos][i] == -1)ch[pos][i] = ch[fail[pos]][i];
else {
fail[ch[pos][i]] =ch[fail[pos]][i];
Q.push(ch[pos][i]);
}
}
}
int query(char s[]) {
int len = strlen(s), pos = root,ans = 0;
for (int i = 0; i<len; i++) {
int tmp = ch[pos][s[i]-'a']; pos = tmp;
while (tmp!=root) {
ans += end[tmp]; end[tmp] = 0;tmp = fail[tmp];
}
}
return ans;
}
}AC;
char s1[1100000];
int main() {
int t,n;
cin>>t;
while (t--) {
scanf("%d",&n);
AC.init();
for (int i = 1; i<=n; i++) {
scanf("%s",s1);
AC.insert(s1);
}
AC.get_fail();
scanf("%s",s1);
printf("%d\n",AC.query(s1));
}
}