[USACO15FEB][AC自動機][棧] Censoring G
阿新 • • 發佈:2020-09-07
題面
看到這種匹配題總會想到 \(AC\) 自動機 (
實際我們匹配的時候只需要多加兩個棧:一個用於記錄下一個匹配的位置,一個用於記錄答案,分別記為 \(S_{tmp}\) 和 \(S_{ans}\)
\(S_{tmp}\) 棧頂每加入字串上的一個位置,就將其記錄到 \(S_{ans}\) 中;
如果字串上匹配到了一個子串,兩個棧就都就跳轉到這個子串開頭的位置。
這樣就可以完成匹配了,最後輸出 \(S_{ans}\) 即可。
程式碼
# include <iostream> # include <cstdio> # include <string> # include <queue> # define MAXN 1000005 int trie[MAXN][26], cntT; int isEnd[MAXN], fail[MAXN]; int ansS[MAXN], tmpS[MAXN], topS; void Insert(std::string s){ int now = 0, len = s.length(); for(int i = 0, ch; i < len; i++){ ch = s[i] - 'a'; if(!trie[now][ch]){ trie[now][ch] = ++cntT; } now = trie[now][ch]; } isEnd[now] = len; } void InitFail(){ std::queue<int>Q; for(int i = 0; i < 26; i++){ if(trie[0][i]){ fail[trie[0][i]] = 0; Q.push(trie[0][i]); } } while(Q.size()){ int now = Q.front(); Q.pop(); for(int i = 0; i < 26; i++){ if(trie[now][i]){ fail[trie[now][i]] = trie[fail[now]][i]; Q.push(trie[now][i]); } else{ trie[now][i] = trie[fail[now]][i]; } } } } void Query(std::string s){ int now = 0, len = s.length(); for(int i = 0, ch; i < len; i++){ ch = s[i] - 'a'; now = trie[now][ch]; tmpS[++topS] = now; ansS[topS] = i; if(isEnd[now]){ topS -= isEnd[now]; // 查到一個單詞直接跳到單詞開頭重新匹配 if(!topS){ now = 0; } else{ now = tmpS[topS]; } } } } int main(){ std::string s, t; int n; std::cin>>s>>n; for(int i = 1; i <= n; i++){ std::cin>>t; Insert(t); } InitFail(); Query(s); for(int i = 1; i <= topS; i++){ std::cout<<s[ansS[i]]; } return 0; }