題意﹕給了一字串

,長度為

。設

為一長度

的前綴。我們把一個長度為

的字串

說是

-迴文,若以下條件成立﹕
1)

是一個迴文;
2)

的

前綴和後綴皆是
)
-迴文。根據定義,任意字串(包括空字串)皆為0-迴文。
現在設
 = k)
若且僅若

是一個

-迴文。題目要求
)
。
未進入解之前,首先需要了解一件事。
引理 1﹕對於任何長度為

的字串

,若

是迴文,

是

-迴文的話,那麼

的長度為

的後綴也是

-迴文,並且和

相同。
証明 1:設

為字串

的逆字串。假設

的長度為

的前後綴分別為

和

。設

,

。那麼

。因為

,

。因此有

和

。若

是

-迴文,則本來

。因此

,即

也是

-迴文。
因此,我們算
)
的時候可以用動態規劃﹕
那麼,答案是求所有前綴迴文,並以上述轉移方程算出陣列和即可。
問題是﹕
如何有效地求所有前綴迴文?
想了幾天,實在沒有頭緒。如果直接算最長前綴迴文的話就很簡單的,只需利用失敗函數和字串

即可。可是它卻不似包含了所有前綴迴文的資訊。因此,放棄了,找到幾個日本人寫的blog,發現他們用了一個算法,叫
Manacher Algorithm。它的目的是求出最長前綴迴文的中點,但計算過程則計算了
所有以某字元可延伸的最長迴文長度。那麼此算法則包括找出所有前綴迴文,當然,也可以用來找最長前綴迴文。先介紹此算法。
Manacher算法
對於長度為

的字串

,定義

為最大整數使得

即以第

字元為單位的最長可延伸成迴文的
半徑。Manacher給了以下定理﹕
定理 2: 對於

,則有
和
。
証明 2: 先証明1)。因為第

字元半徑為

,當中第

字串的半徑是

。若果

不超過

的話,表示第

字元的最長可延伸迴文被第

字元的包含了,則用類似
定理 1可以得出

(即

)。否則

的話,假設

,那麼第

字元的最長可延伸迴文超越了第

字元的。但基於類似
定理 1(我們可以把

定義為任意迴文),第

字元可以再延伸,則

不是最長的,因此有矛盾。所以

(最不突破界限的半徑作為其半徑)。
對於2),則可以基於1)的去思考。

但第

字元的半徑則卻可以突破第

字元的半徑。考慮以下字串﹕
01abbaccabbac
| i |
x y
現在設

。可以看到

但

。
那麼,利用
定理 2計算所有字元的半徑會否很高效?首先,留意到對於第

字元,任何第

位經1)去更新數值的時候,已經不用重覆計算

。唯一的情況則是2)發生,而且枚舉

的時候,
2)只會發生在1)之後。因此,當枚舉至

的時候2)發生了,則跟據
定理 2所示,立即跳至第

位計算其半徑。因為定理說明

,因此找出

可直接從

算起。因此可知

的跳躍是隨

的增加而加快的。算法被証明是
)
的。我沒有很小心的去証明,但可以聯想的是

少的話,

雖然增長很慢(每次移很少)但半徑都很少,因此每次迭代都很快完;相反

很大的話,我們很快就可以以一次送代算出大部分

並且

大幅前躍,感覺也很快會完成。
至於編寫的時候,留意上述是適用於偶數長度半徑,但奇數長度半徑又怎樣算出來呢?
這裡的方法是插入dummy點來計算半徑,但每個字元會被多算一次。這方法亦可看作迭代

的時候移動
半步,而枚舉其半徑時也以
半步為單位移動。
計算了

之後可以簡單地找出前綴迴文的末點,然後應用最被初的轉移方程計算答案。
沒有留言:
張貼留言