luogu P2408 不同子串個數

2022-05-08 01:06:06 字數 1317 閱讀 2586

考慮反向操作,去計算有多少組相同的子串,對於一組大小為k的極大相同子串的集合,ans-=k-1。

為了避免重複計算,需要一種有效的,有順序的記錄方案。

比如說,對於每乙個相同組,按其起始點所在的位置排序,對於除了第乙個串以外的串,均記-1的貢獻。

但這種東西是非常難以快速統計的。

但是,可以對於每乙個相同組,按其所在的字尾字典序排序,對於除了第乙個串以外的串,均記-1的貢獻。

下面引用別人的一段話,主要是利用lcp來快速統計了不用長度相同組。

最後再強調一下為什麼只需要統計height[k],而不需要和之前所有的字尾均計算lcp。

因為,按照剛才我們的分析。把每乙個相同組看成一條鏈,計數只能發生在邊上。

如果去和前面的再統計一遍的話,顯然是一種錯誤的越級的行為,造成重複統計。

此外,由於按照字典序排序後,再前面的所有串中,與它相鄰的串顯然是與它lcp最大的串。

一定可以穩穩地不重不漏的對每乙個之前每乙個出現過的過的字首進行統計。

即:按照字典序排序後,如果某個 當前字尾的乙個字首 與前面的某個字尾的乙個字首相同。

那麼一定是下圖這種情況。

紅色代表可能的位置,因為字典序的緣故,與它靠的越緊,相似度越高。

所以 要麼貢獻已經在之前算過了,要麼就會體現在它和與它相鄰串的lcp中。

#include#include#include#include#include#include#include#include#include#define n 1100000

#define l 1000000

#define eps 1e-7

#define inf 1e9+7

#define ll long long

using namespace std;

inline int read()

while(isdigit(ch))

return x*flag;

}char s[n];

int n,m,c[n],x[n],y[n],sa[n],rank[n],height[n];

int main()

ll ans=(ll)n*((ll)n+(ll)1)/(ll)2;

for(int i=1;i<=n;i++)rank[sa[i]]=i;

for(int i=1,k=0;i<=n;i++)

printf("%lld",ans);

return 0;

}

luoguP2408不同子串個數

可以知道每乙個子串都是字尾的字首,那麼對於第 i 小的字尾的貢獻就可以表示為n sa i 1 然而會存在重複的子串,注意height陣列的定義,對於sa i 1 和sa i 只有height i 個子串會被重複計算,每次都減掉就好了 include include includeusing name...

LuoguP2408 不同子串個數(字尾自動機)

題目傳送門 先建好字尾自動機,然後答案就是 sum len u len link u 為什麼這樣是對的?每個狀態所代表的字串是沒有交集的,所以我們只需求出每個狀態有多少個子串。其實在學習構建sam的時候我們學過link的乙個性質,就是len link x 1 min len x 且乙個狀態內的字串按...

P2408 不同子串個數 SA LCP SAM

傳送門 經典的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名的最...