BZOJ2905 背單詞 AC自動機 線段樹

2021-09-11 03:02:02 字數 3480 閱讀 1316

題目鏈結

由於是許可權題,我沒有許可權號,就掛了乙個darkbzoj的鏈結。

題意:給你n

nn個字串,每個串有乙個價值,你要從中選出乙個價值和最大的子串行,使得前面的串是後面串的子串。資料組

數<=10

,總串長

<=3

e5,單

個串

長<=2

e4

資料組數<=10,總串長<=3e5,單個串長<=2e4

資料組數

<=1

0,總串

長<=3

e5,單

個串長<=2

e4。題解:

一看到子串不一定就是sa和sam的題啊,這個題就是用ac自動機的題。

那麼我們就先對於這n

nn個串建出ac自動機。我們考慮如何用ac自動機來判斷乙個串是否是另乙個串的子串。做法是,我們知道,ac自動機上的fail指標的含義是如果當前位置匹配失敗,下一次應該在哪個串的基礎上繼續嘗試匹配。那麼如果乙個串a

aa是另乙個串b

bb的子串,那麼就意味著b

bb在trie樹上的所有節點中,至少有乙個在若干次失配後會到達a

aa在trie樹上的結束節點。那麼如果我們根據fail指標的關係建出fail樹,a

aa串結束節點在fail樹上的子樹內一定有乙個節點是b

bb串在trie樹上的節點。我們可以發現,乙個點表示的串一定是fail樹中的子節點表示的串的乙個子串,同時似乎也是乙個字尾。(總

串長∗l

og

)o(總串長*log)

o(總串長∗

log)

的,可以通過本題。

**:

#include

using

namespace std;

int t,n,val[

200010

],num,fail[

300010

],hed[

300010

],cnt,xu[

300010

],ed[

300010];

int f[

200010

],ans;

vector<

char

> v[

200010];

queue<

int> q;

char ss[

300010];

struct node

t[300010];

struct edge

a[600010];

struct tree

tr[2000010];

inline

void

insert

(int qwq)

cur=t[cur]

.vis[x];}

}inline

void

get_fail()

}while

(!q.

empty()

)if(cur==1)

break

; cur=fail[cur];}

fail[x]

=cur;

}for

(int i=

0;i<26;

++i)}}

inline

void

add(

int from,

int to)

inline

void

dfs(

int x)

ed[x]

=cnt;

}inline

void

build

(int rt,

int l,

int r)

inline

void

pushdown

(int rt)

}inline

intquery

(int rt,

int le,

int ri)

inline

void

update

(int rt,

int le,

int ri,

int y)

pushdown

(rt)

;int mid=

(l+r)

>>1;

if(le<=mid)

update

(rt<<

1,le,ri,y);if

(mid+

1<=ri)

update

(rt<<1|

1,le,ri,y)

; tr[rt]

.mx=

max(tr[rt<<1]

.mx,tr[rt<<1|

1].mx);}

intmain()

num=1;

ans=0;

memset

(fail,0,

sizeof

(fail));

memset

(hed,0,

sizeof

(hed));

memset

(xu,0,

sizeof

(xu));

memset

(ed,0,

sizeof

(ed));

memset

(f,0

,sizeof

(f))

;scanf

("%d"

,&n)

;for

(int i=

1;i<=n;

++i)

for(

int i=

1;i<=n;

++i)

insert

(i);

get_fail()

;for

(int i=

1;i<=num;

++i)

add(fail[i]

,i);

cnt=0;

dfs(1)

;build(1

,1,num)

;for

(int i=

1;i<=n;

++i)

f[i]

=val[i]

+max

(mx,0)

;update(1

,xu[cur]

,ed[cur]

,f[i]);

}for

(int i=

1;i<=n;

++i)

ans=

max(ans,f[i]);

printf

("%d\n"

,ans)

;for

(int i=

1;i<=n;

++i)

v[i]

.clear()

;}return0;

}

BZOJ 3172 單詞 (AC自動機)

這道題是個裸的ac自動機,但是我還是調了很久qaq。首先如果我們直接用每個單詞來匹配的,時間不是很理想。這道題要用到ac自動機的衍生物 fail樹 我也是做這道題才知道有這個東西 fail樹有這麼乙個結論 乙個字串出現的次數等於以它為根節點的fail樹的子樹中所有節點的cnt的和。根據這個結論,我們...

bzoj3172 單詞 AC自動機

感覺以前寫過。bzoj上不去我也不知道 跑一遍ac自動機,每乙個節點儲存一下屬於多少字串,為它的權值。然後乙個節點表示的字串在整個字典中出現的次數相當於其在fail樹中的子樹的權值的和。ac自動機不要寫掛就好了。ac 如下 include include include define n 11000...

bzoj3172 單詞 AC自動機

有n個單詞組成了一篇文章,求每個單詞在這篇文章中出現了多少次。多個字串匹配的問題,建立ac自動機。如果某個單詞在i節點出現了,那麼在i節點fail指標所指節點也出現過。code include include using namespace std const int max n 1000005 s...