kmp 的 fail 指標指向的是當前點最長的能作為原串的字首的字尾在原串字首上的位置。
i - fail[i] 就是字首 i 的最短迴圈節,也稱為 border。
乙個例題:cf1286e。
ac 自動機的本題是一棵 trie 樹。
ac 自動機的 fail 指標,指向的是當前點代表的串的最長的、作為某個字串的字首出現的字尾所代表的節點。
設乙個串 s 要匹配 ac 自動機上所有的串,那麼乙個 ac 自動機上的串出現,當且僅當這個串在 ac 自動機上的節點的後繼中有節點被 s 訪問過。
一般可以快速處理 乙個串 對 多個串 的貢獻。
1、parent_tree
對於某乙個子串,在某一些位置(為結尾)出現過,出現過的所有位置集合叫做endpos。
parent_tree是這樣一棵樹:乙個節點代表乙個endpos集合,節點上的字串的endpos全部相等且恰為該節點代表的endpos集合;
每乙個節點的endpos集合都是父親節點的子集。
可以發現乙個性質:設每乙個點上的子串的最長串長為maxlen,最短為minlen,則父親的maxlen+1必然等於兒子的minlen,而且minlen~maxlen必然每乙個len都對應乙個子串。
可以證明parent_tree的節點個數為o(n)。
字尾自動機的節點就是parent_tree的節點。
2、字尾自動機
自動機本身是個dag。
通過dag上從初始點出發的每一條路徑,都能組成乙個子串,且所有子串都能被表示出來。
維護下列東西:
fa:parent_tree上的fa。
len:每個節點的maxlen(如上所闡述)(minlen可以通過fa的maxlen來得到)
每次加入乙個字元c,創立乙個新節點:
首先,對於上一次加入的字元的初始點,若它和它的祖先們(parent_tree上的)都沒有兒子c,那就把兒子c連向自己。
然後找到第乙個已經有了兒子c的點x。
考慮這個點的兒子c,稱為ch[x][c]:如果這個len[x]+1=ch[x][c],說明ch[x][c]裡面存的東西正好是符合parent_tree定義的,把新節點的fa連向它;
否則,將x點拆成兩個點u、v:len[u]+1=ch[x][c],len[v]=len[x];然後,v和新節點的fa都是u。u的fa就是x的fa。把連向x的ch中長度滿足條件的連向u,長度不滿足條件的連向v。u和v的ch和x是一樣的。
這樣就維護好了,可以證明邊數也是o(n)的。
3、經典操作
parent_tree從下到上更新:
按照maxlen來對節點基數排序。
求兩個串的最長公共子串:
在自動機上面跑(往下走ch、往上跳fa)就好了。注意nowlen的更新。
4、例題:
xsy3930 最長公共子串對
字串(筆記)
2.格式化字串 3.使用正規表示式 4.字元生成器 建立乙個string 物件 string s new string good 連線字串 或其他型別都用 號 string s s1 s2 查詢a在字串str中的索引位置 int size str.indexof a 首次出現 int size st...
字串筆記
字串 1.字元的讀寫 讀入字元使用 getchar scanf c 輸出字元使用 putchar printf c 對於c語言而言 若用c 還可用cin和cout進行輸入和輸出。ch getchar putchar ch getchar 的速度要快於scanf getchar 可以把回車吞掉 比如第...
字串轉為大寫 字串 筆記
字串的寫法 字串可以用雙引號包裹,也可以用單引號包裹,外面用雙引號,裡面就只能用單引號,反之就只能用雙引號 let str hello world let str1 hello world 反引號,裡面的字串可以換行 let str2 hello world key value it s a lon...