You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
const int N = 10010 * 55; //模式串最长长度,短串
|
|
|
|
|
const int M = 1e6 + 10; //长度为m的文章,长串
|
|
|
|
|
|
|
|
|
|
int n;
|
|
|
|
|
//tr:trie树,每个结点最多26个儿子
|
|
|
|
|
//cnt:trie的每个结点存在的以此结点结尾的字符串个数
|
|
|
|
|
//idx:游标变量,结点号
|
|
|
|
|
int tr[N][26], cnt[N], idx;
|
|
|
|
|
int st[N]; //是不是统计过了,统计过的不用重复统计
|
|
|
|
|
string str; //字符串变量,前面用做输入模式串,最后一个是文章串
|
|
|
|
|
//AC自动机自己的数据结构 q:bfs用的队列 fail:失配指针
|
|
|
|
|
int q[N], fail[N];
|
|
|
|
|
|
|
|
|
|
//构建Trie树
|
|
|
|
|
void insert() {
|
|
|
|
|
int p = 0; //游标变量
|
|
|
|
|
for (int i = 0; i < str.size(); i++) { //遍历模式字符串
|
|
|
|
|
int t = str[i] - 'a'; //计算对应的索引号
|
|
|
|
|
if (!tr[p][t]) tr[p][t] = ++idx; //如果不存在这个结点,则创建之
|
|
|
|
|
p = tr[p][t]; //走进去
|
|
|
|
|
}
|
|
|
|
|
cnt[p]++; //打上字符串完结标识
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//构建AC自动机(填充失配指针)
|
|
|
|
|
void build() {
|
|
|
|
|
int hh = 0, tt = -1;//清空队列,所以前面不需要每次都memset清空q
|
|
|
|
|
for (int i = 0; i < 26; i++) //查找root的所有26个可能存在的儿子
|
|
|
|
|
if (tr[0][i]) //如果该儿子存在
|
|
|
|
|
q[++tt] = tr[0][i]; //把这个儿子放入队列中
|
|
|
|
|
|
|
|
|
|
while (hh <= tt) { //bfs框架
|
|
|
|
|
int p = q[hh++]; //取出队列头,父结点
|
|
|
|
|
for (int i = 0; i < 26; i++) { //尝试找出该结点的所有儿子
|
|
|
|
|
int c = tr[p][i]; //子结点
|
|
|
|
|
//如果不存在,这个的失配指针指向,父节点的失配指针对应的相同字节点下
|
|
|
|
|
if (!c) tr[p][i] = tr[fail[p]][i];
|
|
|
|
|
else {
|
|
|
|
|
//存在依旧指向父节点的失配指针下的同子节点
|
|
|
|
|
fail[c] = tr[fail[p]][i];
|
|
|
|
|
q[++tt] = c;//放入队列
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
cin >> n;
|
|
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
|
|
cin >> str;
|
|
|
|
|
//构建Trie树
|
|
|
|
|
insert();
|
|
|
|
|
}
|
|
|
|
|
//构建AC自动机
|
|
|
|
|
build();
|
|
|
|
|
//读入文章长串
|
|
|
|
|
cin >> str;
|
|
|
|
|
int res = 0;
|
|
|
|
|
//j记录当前树节点的指针,初始是根节点
|
|
|
|
|
for (int i = 0, j = 0; i < str.size(); i++) { //枚举总串str的每一个字母
|
|
|
|
|
int u = str[i] - 'a';
|
|
|
|
|
j = tr[j][u]; //跳到下一个树节点
|
|
|
|
|
int p = j; //每次从当前树节点开始
|
|
|
|
|
|
|
|
|
|
while (p && !st[p]) {
|
|
|
|
|
res += cnt[p]; //累加命中的模式串个数
|
|
|
|
|
cnt[p] = 0; //去除标记
|
|
|
|
|
p = fail[p]; //继续查询
|
|
|
|
|
st[p] = 1; //标识已统计过
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("%d\n", res);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|