題目鏈結
鏈結是洛谷有翻譯的鏈結。
題意:給你乙個字串,有t次詢問,每次問你在整個字串中排名為k的子串是哪乙個。字串長度<=90000,t<=500,只統計本質不同的串。
題解:字尾自動機題,因為字尾自動機有著很強的處理子串的能力。
看到排名第k,我們可能會想到主席樹,但是顯然主席樹是沒法維護具體某個字串,但是主席樹查詢第k大的思想我們是可以使用的。主席樹的方法是看左子樹的size是否比k大,然後來確定進入左子樹還是把k減去左子樹的size進入右子樹。
其實在字尾自動機是我們也是可以用到這個思想的。我們先建出給出字串的字尾自動機,然後我們其實可以發現,字尾自動機上的所有轉移邊構成了乙個dag(也是字尾自動機的性質),那麼對於dag,我們是可以拓撲排序的。這裡可以用一種比較特殊的拓撲排序,這種寫法有點類似與基數排序,我們把長的串排在短的串後面,後建的節點排在先建的節點後面,這樣一定是一種合法的拓撲序。然後我們根據這個拓撲序,我們用反著的拓撲序,求出sam上每個點能到達的所有點的個數,也就是原串中它的字尾個數每個點本身的size都是1,因為從起點到每個點都會形成乙個子串。這樣我們可以像在主席樹上一樣,從根開始走,從小的字母往大的字母嘗試走,看走到哪個字母正好超過當前k,如果當前列舉到的出邊到達的點的size比k小,我們就減去這個size;如果比k大了,就不再減size,轉而輸出那個字母,然後走過去。這樣說可能不是很容易說明白,具體可以看看**。
**
#include
using
namespace std;
int t,n,len[
400010
],fa[
400010
],cnt=
1,rt=
1,lst=
1,ch[
400010][
26];int sz[
400010
],a[
400010
],rk[
400010
],m;
char s[
100010];
inline
void
insert
(int x)}}
inline
void
query
(int x)}}
printf
("\n");
}int
main()
scanf
("%d"
,&t)
;while
(t--
)return0;
}
SPOJ8222 字尾自動機
給出乙個字串,求這個字串長度為1 n的子串的最大出現次數 對於長度為x的子串的答案就是所有長度 x的結點的right值的最大值 於是就從反向字尾樹的葉子開始,定義每個關鍵節點的right初始都為1,然後順著求出所有節點的子樹和就可以了 這裡用到了拓撲排序預處理 於是可以很方便的求出right陣列 或...
SPOJ 1811 LCS 字尾自動機
題意 求兩個串的最大連續子串 乙個串建sam,另乙個串在上面跑 注意如果走了suffix link,sum需要更新為t u val 1 suffix link有點像失配吧,當前狀態s走不了了就到suffix link指向的狀態fa上去,fa是s的字尾所以是可行的,並且有更多走的機會 include ...
SPOJ 1811 LCS 字尾自動機
題意 求兩個串的最大連續子串 乙個串建sam,另乙個串在上面跑 注意如果走了suffix link,sum需要更新為t u val 1 suffix link有點像失配吧,當前狀態s走不了了就到suffix link指向的狀態fa上去,fa是s的字尾所以是可行的,並且有更多走的機會 include ...