AcWing 2766 字尾自動機

2022-04-29 04:51:08 字數 1509 閱讀 2760

前置題目

乙個字串的字尾的所有字首恰好不重不漏地覆蓋了所有的子串,所以我們可以考慮用字尾陣列來做。

比如:babab

排完序後

ab

abab

b

bab

babab

(以下字尾均指排名為 \(i\) 的字尾,而不是原串的第 \(i\) 個字尾)

乙個字尾 \(i\) 的乙個長度為 \(len\) 的字首的出現次數是 使 \(lcp(i,j) \geq len\) 成立的 \(j\) 最大值與最小值之差+1.

在字尾陣列中,我們有 \(lcp(i,j)=\min(lcp(i,i+1),...,lcp(j-1,j)),i

因此 \(lcp(i,j) \leq lcp(i,i+1),...,lcp(j-1,j)\)

因此只需要在height求出左邊和右邊height小於height[i]的第乙個j,即為使 \(lcp(i,j) \geq len\) 的成立的 \(j\) 最小值-1與最大值+1,同時之後的 \(j\) 一定不能使 \(lcp(i,j) \geq len\) 成立。

還要乘乙個子串長度:把子串長度看作高,把 \(|jmax-jmin|\) 看作寬。

由此可以抽象為 131. 直方圖中最大的矩形 來寫。

code

#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

typedef unsigned long long ull;

const int n=1e6+5;

int n,m;

char s[n];

int sa[n],rk[n],ht[n];

// sa[i] 表示排名為i的字尾是 sa[i]

void get_sa()

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

// for(i=1;i<=n;i++) printf("%d ",sa[i]);

// printf("\n");

}void get_ht()

// for(i=1;i<=n;i++) printf("%d ",ht[i]);

// printf("\n");

}int pl[n],pr[n]; // ht 左邊和右邊第乙個更小的數。

void calc(int a,int p)

}ll ans;

int main()

printf("%lld\n",ans);

return 0;

}

字尾自動機

基礎知識 step i 表示的是字串i在原字串中的位置。pareint i 表示root到parent i 的子串是root到i的最長字尾。字尾自動機遍歷可以得到原字串的所有子串。特殊技巧 一 字尾自動機的不同子串數有兩種求法 1.ans step i step parent i 1 i cnt 2...

字尾自動機

常用於處理字串問題,可以高效解決許多字串問題。有點像將乙個字串的所有字尾都建在乙個ac自動機上,但不同的是字尾自動機的節點數最多為2 n,因為它只記錄需要記錄的點,一些沒有記錄東西的點可以視為與下面有價值的節點並在一起,這樣大大降低了時間複雜度和空間複雜度。對於每乙個節點記錄它的後面加上每個字元後字...

字尾自動機

基礎學習 簡潔明瞭的講解 總狀態數不超過2n 12n 1 2n 1 包括初始狀態 統計每個end po sendpos endpos 等價類出現位置數量時,要按長度從長到短的計算cnt cntcn t。那為什麼一定要從長到短呢?比如回文自動機就直接是按照節點編號從大到小計算cnt cntcn t 罪...