Codeforces 1483F - Exam(AC 自動機)
阿新 • • 發佈:2021-06-22
一道 ACAM 的 hot tea
首先建出 ACAM。考慮列舉長串,以及短串在長串中出現的最後位置 \(j\),這個複雜度顯然是 \(\mathcal O(\sum|s_i|)\) 的不會出問題。那麼顯然只有以 \(s_{i,j}\) 為結尾的、長度最長的字串才有可能被統計進答案,否則就不滿足題目中的條件了,而這個字串,顯然就是 \(s_{i,j}\) 對應位置在 fail
樹上向上跳得到的第一個是某個字串結尾的位置所對應的字串,這個可以通過對 fail
樹進行一遍 DFS 求出。
其次,仔細想想就會發現這些字串也並不是所有都真的符合條件,如果我們把這一個個字串看作一個個框,那麼如果一個框被另一個框完全包含,那顯然也是不合法的,這個可以通過記錄個啥陣列然後線性掃一遍把這些不合法的排除掉。但是再即便是排除掉這些不合法的字串之後也有可能出現不合法,或者同一字串被重複統計的情況,因為對於一個未被排除掉的字串 \(s_i[l...r]\)
check
這樣的情況呢?好辦,拿個 map
記錄一下所有字串在 \(s_i\) 中被統計的次數,然後在 map
裡面掃描一遍看所有字串 \(s'\) 在 \(s_i\) 中出現次數是否等於其被統計的次數,如果是則答案加 \(1\),否則說明 \(s'\) 肯定有被排除掉的情況,就不能產生貢獻了。
時間複雜度 \(|S|\log|S|\)
const int MAXN=1e6; int n,ch[MAXN+5][28],ncnt=0,fail[MAXN+5],ed[MAXN+5],ps[MAXN+5]; string s[MAXN+5]; void insert(string s,int id){ int cur=0; for(int i=0;i<s.size();i++){ if(!ch[cur][s[i]-'a']) ch[cur][s[i]-'a']=++ncnt; cur=ch[cur][s[i]-'a']; } ed[id]=cur;ps[cur]=id; } int hd[MAXN+5],to[MAXN+5],nxt[MAXN+5],ec=0,bgt[MAXN+5],edt[MAXN+5],tim; void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;} void getfail(){ queue<int> q; for(int i=0;i<26;i++) if(ch[0][i]) q.push(ch[0][i]); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<26;i++){ if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]); else ch[x][i]=ch[fail[x]][i]; } } for(int i=1;i<=ncnt;i++) adde(fail[i],i); }