CF204E 【Little Elephant and Strings】
阿新 • • 發佈:2021-07-01
tag:SAM,倍增
貢獻一個用廣義\(SAM\),不用大力資料結構的做法
把問題分成兩部分解決
- 求一個字串在多少個\(a_i\)中出現過
- 列舉一個串的一個點\(i\),求以\(i\)為右端點的,在至少\(k\)個\(a_i\)中出現過的字串個數
Case 1
對於第一個問題,可以建廣義\(SAM\),記錄\({a_i}_j\)在\(SAM\)上對應的節點為\({pos_i}_j\)
然後對於一個串\(a_i\)來說,它的貢獻相當於是所有\({pos_i}_j\)在\(SAM\)上構成的一棵虛樹,虛樹每個節點sz+1
那麼具體實現可以用差分,按\(dfs\)序排序,每個\(pos\)的\(sz\)
inline bool cmp(const int &u, const int &v){return dfn[u]<dfn[v];} for(register int i=1; i<=n; i++){ sort(pos[i]+1,pos[i]+len[i]+1,cmp); for(register int j=1; j<=len[i]; j++) sz[pos[i][j]]++; for(register int j=1; j<len[i]; j++) sz[lca(pos[i][j],pos[i][j+1])]--; }
然後跑個\(dfs\)累加差分陣列
void addmk(int x){
for(register int u=fst[x]; u; u=edge[u].nxt)
addmk(edge[u].to),
sz[x] += sz[edge[u].to];
}
然後就求出了每個節點的出現次數
Case 2
考慮一個很暴力的做法
while(x and sz[x]<K) x = fa(x);
即找到第一個\(sz\geq K\)的祖先然後把\(len\)累加進答案
實際上這個過程可以用倍增去代替,因為越往上走,出現的次數肯定越多。所以用類似於求\(lca\)的做法,先跳到最上面的一個\(sz< K\)
int x = pos[i][j];
for(register int k=Log[dep[x]]; compl k; k--)
if(sz[fa[k][x]]<K) x = fa[k][x];
if(sz[x]<K) x = fa[0][x];
ans += len(x);
完整程式碼就不放了,關鍵程式碼全部已經給出來了