首先一定要確定\(sa\)是個什麼東西
\(sa[i]\)表示的是排名為\(i\)的字尾是哪乙個
至於字尾\(i\)的排名是多少,那個是\(rank[i]\)
當然啦最最最難懂的就是基數排序
要是不用基數排序,每次對於乙個二元組直接\(sort\)一下
這樣的複雜度是\(o(nlog^2)\)
對於二元組的基數排序應該是這樣做的:
首先把所有元素按照最後一維丟到依次對應的桶裡面
然後順次取出
再按照第一維依次丟入
再順次取出
這樣就可以排序啦
先把**丟出來
bool cmp(int i,int j,int k)
void getsa()
}
首先,第一次做\(k=0\)時
相當於每個字尾的第二維都是一樣的
所以,直接按照第一維(也就是自己的值)
進行一次基數排序
接下來每次基數排序都要利用到上一次的值
還記得吧,基數排序是先按照第二維從小往大拍
那麼,我們就先把第二維的順序搞出來
首先最小的一定就是沒有第二維的東西
所以我們先把這些數直接丟進陣列裡面
接下來就是有第二維的東西啦
第\(i\)位的第二維是啥?\(rank[i+k]\)
所以,從小到達列舉\(sa\),這樣保證第二維從小往大
那麼,只要\(sa[i]>k\)
就證明它是乙個東西的第二維
所以,把\(sa[i]-k\)丟到陣列裡面去就好啦
這樣的話,按照第二維就拍好啦
再來依次按照第一維丟到桶裡面去
做一遍基數排序就好啦
這樣就能夠求出\(sa\)啦
看起來很簡單誒。。
只是陣列不要搞混了
一定搞清楚每個陣列是幹啥的
比如我的**
\(sa\)是字尾陣列,\(sa[i]\)表示排名為\(i\)的串是哪乙個
\(rank\)相當於排名,\(rank[i]\)表示第\(i\)個串的排名
\(x,y\)兩個陣列是記錄順序的
分別記錄第一維和第二維的排序的順序
\(t\)是桶
這樣我們就很愉快的求出了\(sa\)
還有乙個陣列\(height\)
\(height[i]\)表示串\(sa[i]\)與\(sa[i-1]\)的最長公共字首的長度
比如說,現在要求字尾\(i\)與\(j\)的最長公共字首
那就只需要求\(min(height[i]),i \in [rank[i]+1,rank[j]]\)
因為已經按照字典序排好序啦
\(height\)顯然可以暴力求
但是太不優美
我們有\(height[rank[i]]>=height[rank[i-1]]-1\)
證明(來自\(hihocoder\))
設\(suffix(k)\)是排在\(suffix(i-1)\)前一名的字尾,那麼,我們按照\(rank\)的順序來求\(height\)就行啦則它們的最長公共字首是\(height[rank[i-1]]\)
那麼\(suffix(k+1)\)將排在\(suffix(i)\)的前面(這裡要求\(height[rank[i-1]]>1\),如果\(height[rank[i-1]]≤1\),原式顯然成立)
並且\(suffix(k+1)\)和\(suffix(i)\)的最長公共字首是\(height[rank[i-1]]-1\),
所以\(suffix(i)\)和在它前一名的字尾的最長公共字首至少是\(height[rank[i-1]]-1\)
for(int i=1;i<=n;++i)rank[sa[i]]=i;
for(int i=1,j=0;i<=n;++i)
我現在也不是很熟
以後多做點題我再接著補
SA 字尾陣列
首先一定要確定sa 是個什麼東西 sa i 表示的是排名為 i 的字尾是哪乙個 至於字尾 i的排名是多少,那個是ra nk i 當然啦 最最最難懂的就是基數排序 要是不用基數排序,每次對於乙個二元組直接so rt一下 這樣的複雜度是o nlog 2 對於二元組的基數排序應該是這樣做的 首先把所有元素...
字尾陣列SA
給定乙個字串s,按字典序排序s的所有子串 鬼知道什麼思想,好像沒有什麼思想。哦,想起來了,是倍增。考慮最簡單的字尾間o n o n 比較和快排o nlog n o n logn 總複雜度o n2lo gn o n 2log n 考慮優化字串間的比較,用倍增的思想,假設k 2 k 2 長度的已經比完了...
字尾陣列SA
原理 其本質就是把字串的所有字尾進行排序。用普通排序需要o nlogn 但是字串比較和數字比較不同,所以實際需要o n nlogn 為了讓這個過程快一點,所以有了倍增演算法,o nlogn 和dc3演算法,o n 倍增演算法比較簡單,也比較好寫,具體可以參考這個大佬的部落格。dc3演算法複雜一點,但...