bzoj3940
AC自动机
复习一下。。。 可惜又写错了
我们发现就是把单词建成ac自动机,然后把串在ac自动机上跑一遍,每到一个单词结束点就删除,删除是利用栈,每次弹出单词长度个字符就可以了
发现两个小问题,strlen很慢,不能写在循环里,danger必须在构造fail时全部传递好,否则在匹配时跑fail会达到n^2
至于这里danger为什么不转移,我也不是很清楚。。。大概是因为使用了trie图优化,并且不是统计单词出现次数,只是希望尽量找到靠前的单词删除
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, top; char s[N], t[N], st[N]; int mark[N], last[N]; struct AC { int root, cnt; int danger[N], child[N][27], fail[N]; void insert() { int now = root, len = strlen(t); for(int i = 0; i < len; ++i) { int p = t[i] - 'a'; if(child[now][p] == 0) child[now][p] = ++cnt; now = child[now][p]; } danger[now] = strlen(t); } void build_fail() { queue<int> q; for(int i = 0; i < 26; ++i) if(child[root][i]) q.push(child[root][i]); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < 26; ++i) { if(child[u][i] == 0) child[u][i] = child[fail[u]][i]; else { fail[child[u][i]] = child[fail[u]][i]; q.push(child[u][i]); } } } } void put_string() { int now = root, len = strlen(s); for(int i = 0; i < len; ++i) { st[++top] = s[i]; now = child[now][s[i] - 'a']; last[top] = now; top -= danger[now]; now = last[top]; } } } ac; int main() { scanf("%s%d", s, &n); for(int i = 1; i <= n; ++i) { scanf("%s", t); ac.insert(); } ac.build_fail(); ac.put_string(); int cnt = 0; for(int i = 1; i <= top; ++i) printf("%c", st[i]); return 0; }