1. 程式人生 > 其它 >[luoguP2375] [NOI2014] 動物園

[luoguP2375] [NOI2014] 動物園

題目連結

其實題意還挺難理解的。。。

其實就是定義了一個數組,叫做 \(num[i]\)

假設字串為 \(s = abcababc\)

那麼\(num[4] = 1\), 因為在字首子串\(s[1, 4] = abca\) (我這裡下標是從1開始)中字尾\(a\)與字首\(a\)相同所以為1

假設字串為 \(s = aaaa\)

那麼\(num[4] = 2\), 雖然\(s[1, 4] = aaaa\) 擁有\(a, aa, aaa, aaaa\)四個字首,和\(aaaa, aaa, aa, a\)四個字尾
但是\(aaa\)字首與\(aaa\)字尾有重疊部分所以不算,\(aaaa\)同理,之後\(aa\)

\(a\)

(做完這道題之後我對kmp的next陣列的理解大大提升了!)

首先我們先要知道next陣列到底是在幹嘛。
我們先從next陣列的目的是什麼出發,next陣列是為了減少失配時的重新匹配數。
就相當於失配時,是將匹配串移動next[i]的距離而不是僅僅移動一格進行重新匹配。

為什麼可以移動next[i]的距離?因為next[i]的定義就是[1, i]的子串的字尾與字首的最長匹配長度。(因為下標從1開始,所以長度就其實是下標)

也就是說這段字尾與字首的一段是完全相等的。

所以如果這個位置的下一個位置失配了,我們就可以跳到字首中與這一段完全相等的位置也就是next[i],從而減少重新匹配的次數,達到線性複雜度。

於是我們重新看這道題,這道題求的是\([1, i]\)的字串中的字尾與字首相同但不重疊數的字尾數。

我們只知道\(next[i]\)的定義,但是next陣列跟這個似乎完全扯不上關係啊。

這裡就比較思維了, 首先如果\(next[i] != 0\)的話,說明這個子串肯定有為\([1, next[i]]\)的公共前後綴,
也肯定有\([1, next[next[i]]]\)的公共前後綴,.....於是我們發現,這個不就是我們要求的重疊的\(num[i]\)嗎,所以就是求多少次到next[i]為0。

這裡可以舉個例子,假設$s[1, 13] = abcabcdabcabc$, $next[13] = 6$
所以[1, 13]有[1, 6]的公共前後綴,也會有$[1, 3]$的公共前後綴。是不是很神奇!
(其實我們從next陣列的定義出發就能發現這個規律了,但是我想了好久,還是太菜了www)