记录每一个点建自动机时候的访问次数。 建Fail树,然后节点子树的大小即为当前点出现的次数。
Fail神奇l的特性:所有以x节点代表的字符串结尾的字符串节点,都在x的子树中。#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> using namespace std; const int maxl = 55; const int maxn = 1e6+5; int ch[maxn][30], flag[maxn]; int sz, root, ans = 0; int n, fail[maxn]; inline int idx(char x) { return x - 'a' + 1; } inline void insert(char a[]) { int now = root; int l = strlen(a); for(int i = 0; i < l; i++) { int x = idx(a[i]); if(!ch[now][x]) ch[now][x] = ++sz; now = ch[now][x]; } flag[now]++; } int q[maxn*5], head, tail; inline void get_fail() { head = tail = 0; for(int i = 1; i <= 26; i++) if(ch[0][i]) q[tail++] = ch[0][i]; while(head < tail) { int now = q[head++]; for(int i = 1; i <= 26; i++) { if(!ch[now][i]){ ch[now][i]=ch[fail[now]][i]; continue; } fail[ch[now][i]] = ch[fail[now]][i]; q[tail++] = ch[now][i]; } } } bool vis[maxn]; void ac(char a[]) { int l = strlen(a), now = root; for(int i = 0; i < l; i++) { vis[now] = 1; int x = idx(a[i]); int y = ch[now][x]; while(y && !vis[y]) { vis[y] = 1; ans += flag[y]; y = fail[y]; } now = ch[now][x]; } } char s[maxn], a[maxn]; void clear() { ans = sz = root = 0; memset(ch, 0, sizeof(ch)); memset(vis, 0, sizeof(vis)); memset(fail, 0, sizeof(fail)); memset(flag, 0, sizeof(flag)); } int main() { int T; scanf("%d", &T); while(T--) { clear(); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%s", a); insert(a); } get_fail(); scanf("%s", s); ac(s); printf("%d\n", ans); } return 0; }
bzoj3172 ac自动机fail树应用
最新推荐文章于 2019-02-25 20:55:02 发布