給你乙個長為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 處出現...