P2408 不同子串個數 SA LCP SAM

2021-10-07 12:48:54 字數 2366 閱讀 3166

傳送門

經典的sa−

lc

psa-lcp

sa−lcp

題目。顯然所有子串數目為n(n

+1)2

\dfrac

2n(n+1

)​。因此我們只需知道重複的子串有多少個。

根據l cp

lcplc

p我們知道利用lcp

lcplc

p求出的hei

ght[

i]=l

cp(i

,i−1

),即排

名第i名

和第i−

1名的最

長公共前

綴height[i]=lcp(i,i-1),即排名第i名和第i-1名的最長公共字首

height

[i]=

lcp(

i,i−

1),即

排名第i

名和第i

−1名的

最長公共

字首,他們的長度即是重複的子串個數,這樣求的正確性是因為要找到重複的子串,首先兩個子串下標必須不一樣,且長度一樣,字母完全一樣,所以根據排名第i

ii名和第i−1

i-1i−

1名是字典序最接近的可以知道hei

ght[

i]

height[i]

height

[i]求代表重複子串個數,求和便可得到重複子串總數。

所以a ns

=n(n

+1)2

−∑i=

1nhe

ight

[i

]ans=\dfrac-\sum\limits_^n height[i]

ans=2n

(n+1

)​−i

=1∑n

​hei

ght[

i]

#include

#include

#include

#include

using

namespace std;

const

int n=

1e6+5;

char s[n]

;int n,sz,sa[n]

,rk[n]

,tp[n]

,b[n]

,ht[n]

;typedef

long

long ll;

void

qsort()

voidsa(

)}void

gethight()

}int

main()

upd

ate:

update:

update

: 下面是sam

samsa

m做法,其實sam

samsa

m也有兩種做法,

一種是:結點排序後拓撲跑dpdp

dp。一種是:利用性質直接計算:ans

+=le

n[np

]−le

n[fa

[np]

]ans+=len[np]-len[fa[np]]

ans+=l

en[n

p]−l

en[f

a[np

]]。下面只給出第一種。

#include

using

namespace std;

typedef

long

long ll;

const

int n=

2e6+

5,m=

2e4+

5,inf=

0x3f3f3f3f

,mod=

1e9+7;

#define mst(a) memset(a,0,sizeof a)

#define lx x<<1

#define rx x<<1|1

#define reg register

#define pii pair

#define fi first

#define se second

#define pb push_back

char s[n]

;int a[n]

,b[n]

;struct sam}}

void

build()

void

solve()

printf

("%lld\n"

,dp[1]

-1);

}}sam;

intmain()

洛谷 P2408 不同子串個數

鏈結 p2408 題意給你乙個長為 n 的字串 s 求本質不同的子串的個數。分析這是乙個經典字串問題。我們難以用 kmp 或 ac 自動機來做,所以只能考慮把 s 的 sa 跑出來。這樣任意乙個子串都是 s 某乙個字尾的乙個字首,由於有 ht 這樣有用的東西存在,所以我們就直接看排序後的字尾。我們發...

P 2408 本質不同的字串的個數

1.題目鏈結。求乙個字串本質不同的字串有多少個?本質不同定義為 兩個字串不相等。2.這個問題其實十分的簡單,從字尾陣列的角度來看,對於每乙個sa i 我們知道sa i 代表排名為i的這個字尾所在的位置,假設是j,那麼這個字尾的長度就是n j.他有n j個字首,這些字首都是這個字串的子串,可以證明 所...

luogu P2408 不同子串個數

考慮反向操作,去計算有多少組相同的子串,對於一組大小為k的極大相同子串的集合,ans k 1。為了避免重複計算,需要一種有效的,有順序的記錄方案。比如說,對於每乙個相同組,按其起始點所在的位置排序,對於除了第乙個串以外的串,均記 1的貢獻。但這種東西是非常難以快速統計的。但是,可以對於每乙個相同組,...