[CF316G3]Good Substrings(廣義SAM)
阿新 • • 發佈:2020-10-04
題面
http://codeforces.com/contest/316/problem/G3
題解
前置知識
可以建出這n+1個字串(即s以及所有的p)的廣義SAM。
我們可以在廣義SAM上維護出各個SAM結點分別在\(s,p_1,p_2,…,p_n\)中的出現次數。下稱\(s=p_0\),並設\(l_0=1,r_0=inf\)。
具體做法就是,首先把\(p_0\)到\(p_n\)建成一棵trie,然後在trie上進行BFS。若當前BFS到的trie節點u,是\(p_{i_1},p_{i_2},…,p_{i_m}\)的字首(也就是說,有且僅有\(p_{i_1},…,p_{i_m}\)
然後,在SAM的fail樹上自底向上DFS,每次執行
for(int k = 0;k <= n;k++)f[fail[u]][k] += f[u][k];
最後得到的\(f[i][j]\)就表示SAM節點i在\(p_j\)中出現的次數啦。
統計答案時,只需計入滿足所有\(l_j<f[i][j]<r_j(0{\leq}j{\leq}n)\)
總時間複雜度\(O(n(\sum{|p_i|}+|s|))\)。
程式碼
#include<bits/stdc++.h> using namespace std; #define rg register #define In inline #define ll long long const int N = 50000; const int SN = 550000; In int read(){ int s = 0,ww = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();} while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();} return s * ww; } int n,l[10+5],r[10+5],loc[SN+5]; char s[N+5]; struct SAM{ int cnt,nx[2*SN+5][26],len[2*SN+5],fail[2*SN+5]; int f[2*SN+5][11]; void clear(){ fail[0] = -1; } int extend(int last,int id){ int cur = ++cnt; int p; len[cur] = len[last] + 1; for(p = last;p != -1 && !nx[p][id];p = fail[p])nx[p][id] = cur; if(p == -1)fail[cur] = 0; else{ int q = nx[p][id]; if(len[q] == len[p] + 1)fail[cur] = q; else{ int clone = ++cnt; len[clone] = len[p] + 1; fail[clone] = fail[q]; memcpy(nx[clone],nx[q],sizeof(nx[clone])); fail[cur] = fail[q] = clone; for(;p != -1 && nx[p][id] == q;p = fail[p])nx[p][id] = clone; } } return cur; } In ll count(int u){ return (ll)len[u] - (ll)len[fail[u]]; } vector<int>link[2*SN+5]; void dfs(int u){ for(rg int i = 0;i < link[u].size();i++){ int v = link[u][i]; dfs(v); for(rg int k = 0;k <= n;k++)f[u][k] += f[v][k]; } } void solve(){ ll ans = 0; for(rg int i = 1;i <= cnt;i++)link[fail[i]].push_back(i); dfs(0); for(rg int i = 1;i <= cnt;i++){ ll b = 1; for(rg int j = 0;j <= n;j++)if(f[i][j] < l[j] || f[i][j] > r[j]){ b = 0;break; } ans += b * count(i); } cout << ans << endl; } }S; struct Trie{ int nx[SN+5][26]; vector<int>flag[SN+5]; int cnt; void insert(char s[],int id){ int ls = strlen(s + 1); int u,i; for(u = 0,i = 1;i <= ls;i++){ if(!nx[u][s[i]-'a'])nx[u][s[i]-'a'] = ++cnt; u = nx[u][s[i]-'a']; flag[u].push_back(id); } } queue<int>q; void build(){ S.clear(); q.push(0); while(!q.empty()){ int u = q.front(); q.pop(); for(rg int i = 0;i < 26;i++)if(nx[u][i]){ int v = nx[u][i]; loc[v] = S.extend(loc[u],i); q.push(v); for(rg int j = 0;j < flag[v].size();j++) S.f[loc[v]][flag[v][j]]++; } } } }T; int main(){ scanf("%s",s + 1); T.insert(s,0); l[0] = 1,r[0] = N; n = read(); for(rg int i = 1;i <= n;i++){ scanf("%s",s + 1); l[i] = read(),r[i] = read(); T.insert(s,i); } T.build(); S.solve(); return 0; }