P3121 [USACO15FEB]Censoring G
这道题很明显是一道AC自动机的题目。
可以先将AC自动机板子打出来,打出来后该如何做这到题?可以考虑暴力做法,一个while循环一直扫描,每次扫描到了直接删除,但很明显,这样是会超时的。
通过标签观察我们发现,重新出现的单词是跟前面的部分没有关系的,那么我们就可以用栈来维护,一个栈来维护没有被删除的字符,另一个栈来维护AC自动机的下标
代码
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N = 1e6 + 5, INF = 0x3f3f3f3f;
char str[N], s[N]; int tr[N][26], idx, cnt[N], net[N], len[N]; int stk1[N], stk2[N], top; queue<int> q;
void insert() { int p = 0; for (int i = 0; str[i]; i++) { int t = str[i] - 'a'; if (!tr[p][t]) tr[p][t] = ++idx; p = tr[p][t]; } cnt[p] = strlen(str); }
void build() { for (int i = 0; i < 26; i++) if (tr[0][i]) q.push(tr[0][i]); while (!q.empty()) { int t = q.front(); q.pop(); for (int i = 0; i < 26; i++) { int p = tr[t][i]; if (!p) tr[t][i] = tr[net[t]][i]; else { net[p] = tr[net[t]][i]; q.push(p); } } } }
int main() { scanf("%s", &s); int n = 1; for (int i = 1; i <= n; i++) { scanf("%s", &str); insert(); } build(); for (int i = 0, j = 0; s[i]; i++) { int t = s[i] - 'a'; j = tr[j][t]; stk1[++top] = t; stk2[top] = j; if (cnt[j]) { top -= cnt[j]; if (!top) j = 0; else j = stk2[top]; } } for (int i = 1; i <= top; i++) printf("%c", stk1[i] + 'a'); return 0; }