制胡竄考前總結

2022-04-10 03:36:06 字數 3228 閱讀 8461

利用了回文串的對稱性質,\(o(n)\)的時間複雜度就可以求出以每個點作為回文中心時最長回文串的長度

個人習慣\(mc\)的值為回文串長度,而不是回文串長度+1

int n,mc[maxn<<1],n;

char s[maxn],d[maxn<<1];

inline void manacher()

}

常見用法是先求出\(mc\),然後根據題目要求和其他資料結構和演算法配合使用,也有直接用\(mc\)的

luogu-4555 [國家集訓隊]最長雙回文串

luogu-1659 [國家集訓隊]拉拉隊排練

還有些題目要在\(manacher\)演算法的過程中進行操作

luogu-4287 [shoi2011]雙倍回文

luogu-3501 [poi2010]ant-antisymmetry

\(sa[i]\):排名為\(i\)的字尾在原串的位置

\(rk[i]\):在原串位置為\(i\)的字尾的排名

\(h[i]\):排名為\(i\)的字尾和排名為\(i-1\)的字尾最長的字首長度

\[lcs(i,j) = min(h[k]) (rk[i]< k \le rk[j])

\]感覺沒什麼好說的,板子背熟,熟悉各個陣列的意義,其他的就沒什麼了

inline void qsort()

inline void getsa()

}inline void geth()

一部分題目:

luogu-3809 【模板】字尾排序

luogu-2463 [sdoi2008]sandy的卡片

luogu-2178 [noi2015]品酒大會

其實直接點這個就行了:

字尾陣列

貼一下板子吧,有個常數優化,寫在注釋裡了

inline void getnex()

}

注意我這個版本的匹配方式是:字串下標從1開始,每次嘗試\(s[i+1]\)與\(p[j+1]\)匹配。

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

}

kmp演算法

學習資料的話,感覺oi wiki上的俄文講解翻譯比陳立傑的ppt講的更容易讓人理解,當然clj的ppt是在冬令營講課時候用的,沒有真人講解難以理解也很正常。。。

\(endpos(x)\):子串\(x\)的結束位置集合

字尾自動機上的每乙個狀態都代表著乙個\(endpos\)等價類,即結束位置集合相同的子串們

設\(len[x]\)表示屬於等價類\(x\)的子串中,最長的子串的長度,同理,\(minlen[x]\)代表其中最短的子串的長度

可以發現,對於乙個子串的所有字尾,字尾長度越短,其\(endpos\)大小單調不減。也就是說,根據字尾自動機狀態的定義,每個狀態所表示的子串一定是長度連續的、某個子串的一些字尾

每個狀態\(x\)都有乙個字尾鏈結\(link[x]\),其指向的節點\(y\)代表的子串是\(x\)所代表子串的字尾,由於\(y\)的\(endpos\)要比\(x\)的\(endpos\)大,使得他們分成了兩個不同的狀態,並由\(link[x]\)鏈結。根據上面的那條性質,滿足\(len[y]+1==minlen[x]\)

在原串末尾新插入乙個字元\(c\)的時候,要新建乙個節點\(cur\),其代表的就是新串這個子串和他的所有滿足\(endpos\)大小等於\(1\)的字尾們。設前乙個狀態為\(las\),對於\(las\)和他的每個字尾,都要新建乙個向\(cur\)的轉移

但是,如果\(las\)的某個字尾\(p\)已經有字元\(c\)的轉移了,設轉移到\(q\),這個時候要分兩種情況考慮:

\(len[q]==len[p]+1\):由於我們新加的那個\(cur\)也是\(len[cur]=len[p]+1\),所以就相當於把\(q\)的\(endpos\)集合加入乙個新的位置,直接讓\(st[cur].link=q\)就好了

\(len[q]>len[p]+1\):也就是說,在我們加入\(cur\)之前,原本的長為\(len[p]+1\)的子串和一些長度大於\(len[p]+1\)的子串有同樣的\(endpos\)集合,非常的和諧。但是在我們加入\(cur\)之後,長為\(len[p]+1\)的子串的\(endpos\)集合多了1,和原來不一樣了。我們就要強制把\(len[p]+1\)的和\(>len[p]+1\)的分成兩個點,也就是要轉殖出乙個新的點\(clo\)。這個點的\(len[clo]=len[p]+1\),\(las[clo]=las[q]\),原來\(q\)的轉移\(clo\)也全部滿足,最後\(q\)和\(cur\)的\(link\)指向\(clo\)

inline void extend(char c)

} las=cur; // 不要忘記

}

① 以每個狀態為字首的子串數量(也就是不同子串數量)

對於狀態\(x\)來說,設他作為字首的子串數量為\(d[x]\),列舉他的所有轉移,得

\[d[x]=1+\sum_

\]②以每個狀態為字首的子串總長度(也就是不同子串總長度)

對於狀態\(x\)來說,設要求的為\(ans[x]\),轉移一次就相當於他對所有轉移的串都產生了長度1的貢獻,總共產生了\(d[x]\)的貢獻,在累加上之後的貢獻,得

\[ans[x]=d[x]+\sum_

\]③每個狀態所代表的\(endpos\)集合的大小(也就是子串的出現次數)

注意不要把這個問題和問題①搞混了

要解決這個問題,首先我們要在每次新建乙個節點的時候判斷,如果它不是轉殖出來的,就讓他的\(siz\)(用來記錄答案)\(++\)

根據字尾鏈結\(link\)的定義,乙個點的\(endpos\)集合是其\(link\)所指向節點的\(endpos\)集合的子集,也就是說\(siz[st[x].link]+=siz[x]\)

注意以上問題對於點的dp順序是要按照長度從長到短進行的,所以要先排一下序

for(int i=1;i<=tot;i++) tax[st[i].len]++;

for(int i=1;i<=n;i++) tax[i]+=tax[i-1];

for(int i=1;i<=tot;i++) rk[tax[st[i].len]--]=i;

九省聯考 2018 制胡竄

對於乙個字串 s 我們定義 s 表示 s 的長度。接著,我們定義 s i 表示 s 中第 i 個字元,s 表示由 s 中從左往右數,第 l 個字元到第 r 個字元依次連線形成的字串。特別的,如果 l r 或者 l 1,s 或者 r 1,s 我們可以認為 s 為空串。給定乙個長度為 n 的僅由數字構成...

八省聯考2018 制胡竄

首先,本題parent tree上樹上倍增 線段樹合併找出每個點的 text 集合應該是沒得說的。於是我們現在考慮知道了 text 集合以及詢問串長度 len 怎麼求出答案。首先,乙個正常人稍微想想,都應該得出正難則反的推論,因為無論怎麼說不合法的劃分明顯要來得比較工整。於是問題轉化為割兩刀,能否切...

考前總結小本本

學了兩年oi,記一下容易犯錯和忘記的地方 1.資料特別大或者特別小都可以考慮預處理。特別是多組資料,資料很多的情況 2.注意不要把兩個迴圈變數套一塊 很容易忘記 3.注意不要開錯變數的型別 4.區域性變數和全域性變數不要一起開,同時出現並同時使用肯定會錯 5.函式有返回1,但是不要忘記其他情況返回0...