P3121 [USACO15FEB]Censoring G題解
阿新 • • 發佈:2021-01-03
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; }