SPOJ REPEATS 字尾陣列

2022-08-31 04:00:10 字數 2883 閱讀 2309

題意:首先定義了乙個字串的重複度。即乙個字串由乙個子串重複k次構成。那麼最大的k即是該字串的重複度。現在給定乙個長度為n的字串,求最大重複次數。

思路:根據《字尾陣列——處理字串的有力工具》的思路,先窮舉長度l,然後求長度為l 的子串最多能連續出現幾次。首先連續出現1 次是肯定可以的,所以這裡只考慮至少2 次的情況。假設在原字串中連續出現2 次,記這個子字串為s,那麼s 肯定包括了字元r[0], r[l], r[l*2],r[l*3], ……中的某相鄰的兩個。所以只須看字元r[l*i]和r[l*(i+1)]往前和往後各能匹配到多遠,記這個總長度為k,那麼這裡連續出現了k/l+1 次。最後看最大值是多少。

這裡說下我對這個思路的理解,首先列舉長度l沒什麼好說,然後假設位置i屬於答案字元子串最前段內,那麼考慮答案是重複2次以上,那麼位置i一定和位置i+l匹配,如果往後匹配的最長公共字首為len,那麼以i為起點長度為len的子串重複了len/l+1次,但是這只是i為起點的情況,考慮i不為起點的情況,如果len不是l的倍數,說明len%l的部分是多餘的部分,該部分不足夠讓子串再重複一次,所以我們可以考慮從i和i+l往前匹配,如果可以匹配[pre=l-(len%l)]個字元,那麼就可以再多重複一次,相當於答案字元的起點是i-pre,重複次數為(len/l+1)+1,後面的+1相當於之前多餘的字元和i往前匹配湊足了一次重複次數。那麼就可以再判斷位置i-pre和i+l-pre的最長公共字首是否大於等於需要湊足的字元(pre),或者往前直接暴力匹配是否能匹配夠pre。可能會問為什麼只需要往前匹配pre個字元就可以判斷了,而不是往前匹配更遠那答案不是更優了嗎?,假如i和i+l往前可以匹配pre+k*l個字元,那麼該答案肯定在i列舉到i-k*l就被計算過了,所以只需匹配前pre個字元就可以了。對於求某兩個位置的最長公共字首和用字尾陣列的height用rmq預處理出來,然後就可以o(1)查詢了。

窮舉長度l 的時間是n,每次計算的時間是n/l。所以整個做法的時間複雜度是o(n/1+n/2+n/3+……+n/n)=o(nlogn)。

#define _crt_secure_no_deprecate#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long

intll;

const

int maxn = 50000 + 5

;int cmp(int *r, int a, int b, int

l)int

wa[maxn], wb[maxn], wv[maxn], ws[maxn];

void da(int *r, int *sa, int n, int

m)

for (i = 0; i < n; i++)

for (i = 1; i < m; i++)

for (i = n - 1; i >= 0; i--)

for (j = 1, p = 1; p2, m =p)

for (i = 0; i < n; i++)

}for (i = 0; i < n; i++)

for (i = 0; i < m; i++)

for (i = 0; i < n; i++)

for (i = 1; i < m; i++)

for (i = n - 1; i >= 0; i--)

for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)

}return;}

intrank[maxn], height[maxn],sa[maxn];

void calheight(int *r, int *sa, int

n)

for (i = 0; i < n; height[rank[i++]] =k)

return;}

int rmq[maxn],mm[maxn],best[20

][maxn];

void initrmq(int

n)

return;}

int askrmq(int a, int

b)int lcp(int a, int

b)

return(height[askrmq(a + 1

, b)]);

}int

r[maxn], t, len;

char

str;

void

solve()

ans =max(ans, tmp);}}

printf(

"%d\n

", ans);

}int

main()

r[len] = 0

; da(r, sa, len+1, 3); //

因為題目輸入只有'a'和'b',所以字元最大為3

calheight(r, sa, len);

for (int i = 1; i <= len; i++)//

初始化化rmq

initrmq(len);//

計算rmq

solve();

}//#ifdef local_time

//cout << "[finished in " << clock() - start << " ms]" << endl;

//#endif

return0;

}

字尾樹 字尾陣列

在字串處理當中,字尾樹和字尾陣列都是非常有力的工具,其中字尾樹大家了解得比較多,關於字尾陣列則很少見於國內的資料。其實字尾陣列是字尾樹的乙個非 常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也不太遜色,並且,它比字尾樹所占用的空間小很多。可以說,在資訊學競賽 中字尾...

字尾樹 字尾陣列

我們考慮將乙個串的所有字尾插入乙個trie中,得到的trie就是字尾trie。我們可以發現,樹上有分叉或者是字尾節點的點的個數是o l en o len o len 個,這個後面解釋,於是把沒有分支並且不是字尾節點的點壓縮到一起,就變成了字尾樹。不難發現,字尾樹可以表示該字串的所有子串。下面分析一下...

字尾陣列入門,字尾陣列模板整理

我自己懶得寫,就是想寫個部落格儲存下大佬的部落格位址 點這模板題 大佬的模板 include include include include include include include include include include include define inf 0x3f3f3f3f d...