傳送門
經典的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的貢獻。但這種東西是非常難以快速統計的。但是,可以對於每乙個相同組,...