[學習筆記]迴文演算法
阿新 • • 發佈:2022-02-21
生命是終將荒蕪的渡口,連我們自己都是過客。
Manacher
Manacher用以解決一類對每個中心求解其左右兩端最長的迴文串。
考慮我們先把所有兩個字元之間都插入一個不在字符集裡的字元,這樣就可以不用考慮中心在字元中間的情況,即可以直接列舉中心。
考慮如何使用已知的資訊操作。
若我們求\(i\)位置的最長迴文半徑,設前面極長迴文串的最右端為中心為第\(j\)個位置,考慮對稱過去為\(p\),則不難發現\(\min(f_p,j + f_j - i)\)一定不大於\(f_i\),我們就可以知道在我們已經掃過的範圍內,以\(i\)位置為迴文中心的迴文串的最長迴文半徑,接著可以之間暴力列舉。
其複雜度為\(O(n)\)。
點選檢視程式碼
s[0] = '~'; a = getchar(); while(a <= 'z' && a >= 'a'){ s[++len] = '|'; s[++len] = a; a = getchar(); } s[++len] = '|'; for(int i = 1;i <= len;++i){ if(m + ans[m] >= i) ans[i] = std::min(m + ans[m] - i,ans[m * 2 - i]); while(s[i - ans[i]] == s[i + ans[i]]) ans[i] ++ ; if(ans[i] + i > m + ans[m])m = i; if(fans < ans[i]) fans = ans[i]; } std::cout<<fans - 1;