洛谷P3966 [TJOI2013]單詞 單詞 (ac自動機 fail樹的應用)
阿新 • • 發佈:2018-09-01
emp c++ lse class 是我 文章 amp 就是 http
目錄
- 洛谷P3966 [TJOI2013]單詞 單詞 (ac自動機 fail樹的應用)
- 概述:
- 參考代碼
洛谷P3966 [TJOI2013]單詞 單詞 (ac自動機 fail樹的應用)
題目鏈接
概述:
ac自動機的fail指針構建成了一顆樹。如果fail[p]指向q。那麽我們假設根到p的字符串為str, 根到q的字符串為ttr. 那麽str的後綴就是ttr的前綴, 某字符串在自動機上出現了。
對於這題, 每個在每個單詞插入字典樹的時候一路加加,代表這個單詞的這個前綴出現過。那麽整個自動機就是我們的文章。還有些情況我們需要統計就是單詞作為某些後綴出現的情況。cnt[ fail[x] ] += cnt[x] 這樣我們按深度由深到淺計算貢獻即可(避免重復計算)。同時我們發現整個貢獻計算就是隊列的逆順序。所以我存到了一個棧中。
參考代碼
ps:自動機風格是看著kuangbin的學的
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 7; char buf[MAXN]; int pos[MAXN], n; stack<int>st; struct ACauto { static const int MAXN = 1e6 + 7; int fail[MAXN], ch[MAXN][30], cnt[MAXN], tot, root; int new_node() { for(int i = 0; i < 26; i++ ) { ch[tot][i] = -1; } cnt[tot++] = 0; return tot - 1; } void init() { tot = 0; root = new_node(); } void insert(char *str, int len, int id) { int now = root; for(int i = 0; i < len; i++ ) { if(ch[now][ str[i] - 'a' ] == -1) { ch[now][ str[i] - 'a' ] = new_node(); } now = ch[now][ str[i] - 'a' ]; cnt[now]++; } pos[id] = now; } void get_fail() { queue<int>que; fail[root] = root; for(int i = 0; i < 26; i++ ) { if(ch[root][i] == -1) { ch[root][i] = root; } else { fail[ ch[root][i] ] = root; que.push(ch[root][i]); } } while(!que.empty()) { int now = que.front(); que.pop(); st.push(now); for(int i = 0; i < 26; i++ ) { if(ch[now][i] == -1) { ch[now][i] = ch[ fail[now] ][i]; } else { fail[ ch[now][i] ] = ch[ fail[now] ][i]; que.push(ch[now][i]); } } } } int query(char str[], int len) { int now = root; int res = 0; for(int i = 0; i < len; i++ ) { now = ch[now][ str[i] - 'a' ]; int pos = now; while(pos != root) { res += cnt[pos]; cnt[pos] = 0; pos = fail[pos]; } } return res; } }; ACauto ac; int main() { scanf("%d", &n); ac.init(); for(int i = 1; i <= n; i++ ) { scanf("%s", buf); ac.insert(buf, strlen(buf), i); } ac.get_fail(); while(!st.empty()) { ac.cnt[ ac.fail[st.top()] ] += ac.cnt[ st.top() ]; st.pop(); } for(int i = 1; i <= n; i++ ) { printf("%d\n", ac.cnt[pos[i]]); } return 0; }
洛谷P3966 [TJOI2013]單詞 單詞 (ac自動機 fail樹的應用)