字尾陣列四 重複旋律4

2021-07-24 15:04:16 字數 2645 閱讀 7791

我們知道乙個**旋律被表示為長度為 n 的數構成的數列。

我們把一段旋律稱為(k,l)-重複的,如果它滿足由乙個長度為l的字串重複了k次組成。 如旋律abaabaabaaba是(4,3)重複的,因為它由aba重複4次組成。

小hi想知道一部作品中k最大的(k,l)-重複旋律。

輸入一行乙個僅包含小寫字母的字串。字串長度不超過 100000。

輸出一行乙個整數,表示答案k。

樣例輸入

babbabaabaabaabab
樣例輸出

這次的問題是重複次數最多的連續字串。

先降低難度,不如考慮如何解決如何求乙個串的最大重複次數。

比如說串abababab,既可以是(1,8),也可以是(2,4),最大的是(4,2)。

假如說我們列舉乙個可能的迴圈節長度l(或者k),能不能快速判斷這個l是否合法呢?

似乎是求原串和原串去掉前l個字元後兩個串的lcp(最長公共字首),如果能完全匹配上,就滿足!

比如abababab,檢驗是否是(2,4),就拿abababab和ababab求lcp。

值得一提的是,利用height陣列可以快速求出我們需要的lcp。例如abababab的height陣列如下:

suffix

saheightab7

0abab52

ababab34

abababab16

b80bab61

babab43

bababab25

如果我們要求某兩個字尾的lcp,只要求它們中間的一段height陣列的最小值即可。例如abababab和ababab的lcp就是[6]這段的最小值,即6;bab和bababab的lcp就是[3, 5]這段的最小值,即3;ab和babab的lcp就是[2, 4, 6, 0, 1, 3]這段的最小值,即0。

這個求height陣列某一段最小值的問題,恰好是之前講過的[rmq問題],可以通過o(nlogn)的預處理達到o(1),處理單次詢問;當然使用線段樹等資料結構也是可以的,單次詢問o(logn)。

明白了。回到原問題,那我們肯定是要先列舉(k,l)中的這個l,再列舉起始位置i,計算suffix(i)和suffix(i+l)的lcp,記作lcp(l, i),那麼k(l, i)就等於lcp(l,i)/l + 1。對於所有的迴圈節長度l和起始位置i,最大的k(l, i)就是答案。

不過本題還是有進一步優化的空間。對於確定的l,我們不用列舉所有的起始位置i,而只列舉i是l的整數倍的情況。如果最優串的開始位置恰好在l的倍數上,那我們找到的最大的k就是正確答案。

即使不是,問題也會太糟糕,假如說最優串位置在x,可以想象我們會列舉到x之後的乙個最近位置p,p是l的倍數。並且我們計算出了suffix(p)和suffix(p+l)的lcp,lcp(l, p)那麼此時的k(l, p)=lcp(l, p)/l+1。

對於被我們略過的k(l, p-1), k(l, p-2) ... k(l, p-l+1),它們的上限是k(l, p)+1。

因為它們的起始位置距離p不超過l,所以最多比suffix(p)增加乙個迴圈節。

其次,如果k(l, p-1), k(l, p-2) ... k(l, p-l+1)中有乙個的值是k(l, p)+1的話,那麼k(l, p - l + lcp(l, p) mod l)一定等於k(l, p)+1。(mod是取餘運算)

哦,我有點明白了。k(l, p - l + lcp(l, p) mod l)是乙個分界線,右邊的值因為lcp不夠大,一定不能增加乙個迴圈節。並且如果k(l, p - l + lcp(l, p) mod l)沒有增加迴圈節的話,說明[p - l + lcp(l, p) mod l, p]這段中間匹配出錯,左邊的lcp也跟著雪崩,更不可能增加迴圈節了。

列舉完l後列舉開始位置的時間複雜度是o(n/l)的,所以總複雜度是o(n/1)+o(n/2)+o(n/3)...這個是乙個經典的求和,總複雜度是o(nlogn)的。

#include #include #include #include #include using namespace std;

//file *stream;

string s;

int n;

const int n = 100000 + 50;

int sa[n];//字尾陣列,儲存排序後字尾字串的開頭位置,本身下標對應名次

int rank[n];//名次陣列,儲存排序後字尾字串名次,本身下標對應字串開頭位置

int height[n];//排名相鄰的兩個字尾的最長公共字首

int wa[n], wb[n], wss[n], wv[n];

int cmp(int *r, int a, int b, int l)

void getsa(string r, int *sa, int n, int m)//r為初始輸入,可以對應改為字串陣列,sa為字尾陣列,n為輸入個數+1,m為輸入中的最大值,字元的話可以對應改為ascii碼最大值

} cout << ans << endl;

}int main()

//freopen_s(&stream, "con", "r", stdin);

//system("pause");

return 0;

}

Hiho 123 字尾陣列四 重複旋律4

首先列舉 k,l 中的這個l,再列舉起始位置i,計算suffix i 和suffix i l 的lcp,記作lcp l,i 那麼k l,i 就等於lcp l,i l 1。對於所有的迴圈節長度l和起始位置i,最大的k l,i 就是答案。using system namespace hiho stati...

hihocoder 字尾自動機四 重複旋律6

題目 對於 k in 1,n 求出長度為 k 的子串出現次數最多的出現了多少次 我直到現在才理解字尾自動機上的子樹和是什麼意思 非常顯然的一點是 endpos link u endpos u 考慮到 link u 有多個兒子 於是還需要 endpos 的另外乙個性質 endpos u endpos ...

hihocoder 字尾自動機四 重複旋律7

題目 在 dag 上跑乙個 dp 就好了 設 ans i 表示到了 sam 的 i 位置上所有的子串形成的數的和,之後我們順便記錄乙個方案數 d i 之後我們直接轉移就好了 ans v ans u times 10 w u,v times d u d v d u 答案是 sum ans i incl...