題解 字尾陣列 本質不同字串

2021-09-25 21:48:05 字數 1781 閱讀 3709

給你乙個長為n的字串,求不同的子串的個數

我們定義兩個子串不同,當且僅當有這兩個子串長度不一樣 或者長度一樣且有任意一位不一樣。

子串的定義:原字串中連續的一段字元組成的字串

這道題是一道字尾陣列的結論題。

我們嘗試向sasa

sa陣列以及h陣列的含義:

s a[

i]表示

第i小的

字尾串的

左端點是

什麼

sa[i]表示第i小的字尾串的左端點是什麼

sa[i]表

示第i小

的字尾串

的左端點

是什麼h[i

]b表示

第i個串

以及第i

−1個串

的最長公

共前

綴h[i]b表示第i個串以及第i-1個串的最長公共字首

h[i]b表

示第i個

串以及第

i−1個

串的最長

公共字首

列舉排序之後的字串,低於第i小的字串,它的左端點在sa[

i]

sa[i]

sa[i

]這個位置上。它們一它為端點一共可以組成n−s

a[i]

+1

n-sa[i]+1

n−sa[i

]+1個串,但是如果答案一直累加上這個數的話是一定會有重複的,如何去重呢?

乙個串想要與當前串重複,一定是與當前串有公共字串。

那麼與sa[

i]

sa[i]

sa[i

]有公共字串的串的個數很顯然是h[i

]h[i]

h[i]

。答案為:

∑ i=

1nn−

sa[i

]+1−

h[i]

\sum_^n n-sa[i]+1-h[i]

i=1∑n​

n−sa

[i]+

1−h[

i]為何是對的呢?

當我們列舉到第i小的串的時候,前面i-1個串是相當於已經被記錄好的了,也就是說前i-1個串已經去過重,我們要思考的重複的串就是以第i個串為端點的字串的個數,所以這一波累加之後就是答案

#include

using

namespace std;

const

int n=

1e6+10;

int n;

char s[n]

;int cnt[n]

;// ge shu

int rk[n]

;//pai min

int sa[n]

;//di i xioa de hou zhui de bian hoa

int tmp[n]

;//di er guan jian zi

int rkk[n]

;int height[n]

;signed

main()

for(

int i=

1,j=

0;i<=n;i++

)long

long ans =0;

for(

int i=

1;i<=n;i++

) ans+

=n-sa[i]+1

-height[i]

;printf

("%lld"

,ans)

;return0;

}

字串 字尾陣列

n 字串的長度。m 當前字尾 離散化後 的值域。對於char可以跳過離散化,初值取128即可,對於int要離散化,初值取n即可,初值要保證覆蓋整個值域。sa i 排名為 i 的字尾的起始位置。rk i 起始位置為 i 的字尾的排名。驗證 const int maxn 1000000 10 int n...

字尾陣列 用字尾處理字串

字尾陣列處理的是文字串。我們將文字串的每一條字尾拿出來,按照字典序排序,然後就可以處理字尾陣列了。字尾陣列sa i 表示的就是排名第i位的字尾的第乙個字元所在下標。這可能有點繞口,所以我們用樣例解釋一下,如對於文字串ababa,則字尾為ababa,baba,aba,ba,a,我們排序後就是 a,ab...

NOIP模擬 字串(字尾陣列)

給定兩個字串 s1 和 s2 兩個字串都由 26 個小寫字母中的部分字母構成。現在需要統計 s 2 在 s 1 中出現了的次數。對於 s1 中的每個位置 i 設 st rlen s2 m,若 j 1m s1 i j 1 s 2 j k 最外層中括號為布林表示式 則認為 s2 在 s1 的 i 處出現...