AC自动机入门题
开两个栈
建出trie图 , 处理完失配数组
Ac自动机扫过去 , 第一个栈记扫过的 , 第二个栈记匹配位置
然后ac自动机里面一个end记录以它为结尾单词长度
匹配到就删掉这个单词 , 即栈顶减去其长度,更新trie上当前节点 , 由于新子串仅由删去一个单词后前后拼接而成
所以now更新为原栈顶
最后答案是原文中编号在第二个栈中的字母
code:
#include <iostream> #include <cstring> #include <string> #include <queue> using namespace std; int n; struct node { int end; int vis[26]; int fail; } ac[1000001]; int sta1[1000001] , sta2[1000001]; string s; int cnt = 0; void insert(string s) { int now = 0 , l = s.length(); for(int i = 0 ; i < l ; i++) { if(!ac[now].vis[s[i]-'a']) ac[now].vis[s[i]-'a'] = ++ cnt; now = ac[now].vis[s[i]-'a']; } ac[now].end = l; } void get_fail() { queue <int> q; for(int i = 0; i < 26; i++) if(ac[0].vis[i] != 0) q.push(ac[0].vis[i]); while(!q.empty()) { int now = q.front(); q.pop(); for(int i = 0; i < 26; i++) { if(ac[now].vis[i] != 0) ac[ac[now].vis[i]].fail = ac[ac[now].fail].vis[i] , q.push(ac[now].vis[i]); else ac[now].vis[i] = ac[ac[now].fail].vis[i]; } } } int top = 0; void solve(string s) { int now = 0 , l = s.length(); for(int i = 0; i < l; i++) { now = ac[now].vis[s[i]-'a']; sta1[++top] = now; sta2[top] = i; if(ac[now].end) { top -= ac[now].end; if(!top) now = 0; else now = sta1[top]; } } } int main() { cin >> s; cin >> n; for(int i = 1; i <= n; i++) { string in; cin >> in; insert(in); } get_fail(); solve(s); for(int i = 1; i <= top; i++) cout << s[sta2[i]] ; return 0; }