SPOJ7258 SUBLEX 字尾自動機

2021-09-02 10:58:29 字數 1272 閱讀 2376

題目鏈結

鏈結是洛谷有翻譯的鏈結。

題意:給你乙個字串,有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 ...