3277 3473 串 字尾自動機

2021-08-15 11:14:12 字數 1598 閱讀 3873

description

字串是oi界常考的問題。現在給定你n個字串,詢問每個字串有多少子串(不包括空串)是所有n個字串中至少k個字串的子串(注意包括本身)。

首先建出廣義字尾自動機,建的時候順便預處理每個節點代表的串在多少個字串中出現,預處理的方法和2780是一樣的。然後用f[

i]f [i

]表示

i i

號節點的貢獻,對於出現次數

<

k' role="presentation" style="position: relative;"><

kf[i]

=0f [i

]=

0,否則f[

i]=m

x[i]

−mx[

par[

i]] f[i

]=mx

[i]−

mx[p

ar[i

]]

。但是題目要求的子串是可以重複的,現在計算的只是沒有重複的,所以

i i

節點的實際貢獻還要加上它pa

rent

' role="presentation" style="position: relative;">par

entp

aren

t樹上的祖先的貢獻(這個如果不懂的話要仔細想一想啊)。然後對於每個串,在字尾自動機上跑一遍累加答案即可。

#include

using

namespace

std;

#define ll long long

#define pa pair

const

int maxn=200010;

const

int inf=2147483647;

int read()

while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();

return x*f;

}int tot=1,last;

int son[maxn][26],par[maxn],mx[maxn];

ll f[maxn];

int cnt[maxn];

int mark[maxn],t=0;

void extend(int x)

}last=np;

while(np&&mark[np]!=t)

}char s[100010];

string str[100010];

int len[100010];

struct edgee[maxn];

int len=0,last[maxn];

void ins(int x,int y)

void dfs(int x)

int main()

for(int i=1;i<=tot;i++)f[i]=((cnt[i]>=k)?(mx[i]-mx[par[i]]):0);

for(int i=2;i<=tot;i++)ins(par[i],i);

dfs(1);

for(int i=1;i<=n;i++)

}

字尾自動機

基礎知識 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 罪...