比較模板的題。
題目
給定一個字符串 \(S\),\(n\) 個字符串 \(T_1,T_2,\dots,T_n\),每個串長度都是 \(m\),一個長度為 \(k\) 的有理數序列 \(p_1,p_2,\dots,p_k\) 保證 \(\sum p_i=1\)。每個字符串由前 \(k\) 個小寫字母構成。
我們進行下面的過程:
- 如果存在 \(j(1\le j\le n)\) 滿足 \(T_j\) 是 \(S\) 的子串,那么停止這個過程。
- 否則按 \(p_i\) 的概率將第 \(i\) 個小寫字母加到 \(S\) 的末尾,然后繼續這個過程。
定義 \(f(S,T,p)\) 表示停止的時候 \(S\) 的期望長度。
給一個字符串 \(R\),對 \(R\) 的每個前綴,求出答案。也就是求出 \(f(R[1\dots i],T,p)\) 對 \(i\in [1,|R|]\) 的所有值。
\(n\le 100,nm\le 10000,|R|\le 10^4\),答案對 \(1\ 000\ 000\ 007 取模\)
題解:
一個顯然的做法是建出 \(T_1,T_2,\cdots,T_n\) 的 AC 自動機,則題目相當於在 AC 自動機上隨機游走,問走到葉結點之一的期望次數。
設 \(E(x_i)\) 表示從 AC 自動機上第 \(i\) 個點出發,期望多少次能走到一個葉結點,列方程后高斯消元即得答案。未知數個數達到 \(O(nm)\),時間復雜度 \(O(n^3m^3)\),過不了。
考慮優化未知數個數。觀察方程 \(E(x_u)=1+\sum_{c=1}^k p_c E(x_{\operatorname{next}_{u,c}})\)。
(\(\operatorname{next}_{u,c}\) 表示從點 \(u\) 走 \(c\) 的轉移邊到的結點)中,\(\operatorname{next}_{u,c}\) 要么是 Trie 樹上 \(u\) 的兒子,要么深度不超過 \(u\) 的深度。
考慮樹剖:對每個點 \(u\) 任選一個兒子 \(v\) 作為偏愛兒子進行樹鏈剖分。那這個方程就可以看作把 \(v\) 用 \(u\) 的其他兒子和深度不超過 \(u\) 的深度的結點表示出來。
那么我們發現經過代入,每個結點的答案都可以通過一些鏈頂結點的答案來表示。怎么做呢?我們按從淺到深的順序來做。注意到對一個方程 \(E(x_u)=1+\sum_{c=1}^k p_c E(x_{\operatorname{next}_{u,c}})\),它所涉及到的最深層的結點是 \(u\) 的全部兒子,而它們除了偏愛兒子 \(v\) 以外全是鏈頂結點。而對於所涉及到的深度不超過 \(u\) 的深度的結點,由於我們是按從淺到深的順序,所以一定已經被表出,代入即可。
由於葉子結點不超過 \(n\) 個,所以剖出鏈的個數 \(O(n)\),未知數個數 \(O(n)\),總時間復雜度 \(O(n^3+n^2mk+|R|)\),可以通過。
此外這題還可以使用概率生成函數。
不熟悉概率生成函數的同學可以先做做 歌唱王國 和 硬幣游戲。
首先把輸入的 \(T_1,T_2,\cdots,T_n\) 拿去去重。
先考慮 \(S\) 初始為空的情況怎么做。
記 \(F_i(x)=\sum_{j\ge 0} f_{i,j}x^j,G(x)=\sum_{j\ge 0} g_jx^j\),其中 \(f_{i,j}\) 表示隨機第 \(j\) 次時恰好跟 \(T_i\) 匹配上的概率,\(g_j\) 表示隨機第 \(j\) 次時還沒有結束的概率。
根據概率生成函數的基礎知識,我們要求的是 \((\sum F_i)'(1)\)。
由於 \(g_{j-1}-g_{j}=\sum_i f_{i,j}\),於是有 \(1+xG(x)=G(x)+\sum_i F_i(x)\)。
此外我們根據 \(n\) 個串的信息還能列出 \(n\) 個方程。具體來說,若當前還沒有結束隨機過程,這時我們在串尾接上 \(T_i=T_{i,1}T_{i,2}\cdots T_{i,m}\) 后,隨機過程必然是已經結束了。然而也可能還沒有接完 \(T_i\) 就已經匹配完了。總之:\(G(x)\prod_{k=1}^m(p_{T_{i,k}}x)=\sum_{j=1}^n F_j(x)\sum_{l|T_i[1:l]=T_j[m-l+1:m]}\prod_{k=l+1}^m(p_{T_{i,k}}x)\)。
我們最終要求 \((\sum F_i)'(1)\)。由第一個式子:
\((\sum F_i)(x)=1+(x-1)G(x)\)
\((\sum F_i)'(x)=G(x)+(x-1)G'(x)\)
\((\sum F_i)'(1)=G(1)\)
所以我們求的其實就是 \(G(1)\)。
由后面的式子,\(G(1)\prod_{k=1}^mp_{T_{i,k}}=\sum_{j=1}^n F_j(1)\sum_{l|T_i[1:l]=T_j[m-l+1:m]}\prod_{k=m-l+1}^mp_{T_{j,k}}\)。
此外還有 \(\sum_{j=1}^n F_j(1)=1\)。
\(n+1\) 個方程 \(n+1\) 個未知數,可以解了。最后代入即得 \(G(1)\)。
接下來是 \(S\) 初始不為空的情況,也就是我們給它欽定了一些前綴。
首先如果欽定的前綴里就包含了某個 \(T_i\),那就不用做了。
否則考慮照樣列方程。第一個方程是不變的。
第二個方程如何改變呢?關鍵在於,剛剛列方程時在串尾接上 \(T_i\) 的操作是在哪里都可以做的,如果使用原來的方程就變成了只有開始隨機之后才能接上。實際上還沒開始隨機的時候也可以往后面加 \(T_i\),而這樣對原函數方程的貢獻形如 \(\sum_{k}q_kx^k\)(除 \(x\) 以外都是常數),而代入 \(1\) 以后就徹徹底底變成常數了。
因此每次只有常數項有改變,不用每次都高斯消元,只要矩陣求逆后乘向量即可。
時間復雜度 \(O(n^3+n^2m+nmk+|R|)\)。