A:馬拉車是什么?
Q:是一種求回文子串(你也可以用它來去最長回文子串)的方法(速度很快)
A:有什么意義?
Q:證明了學好寫暴力,走遍天下都不怕的道理
馬拉車算法的精髓就是把之前匹配過的字符串結果放到后面來使用
小技巧
一個回文串它的對稱中心可能是某個字符(aba),也可能是某兩個字符之間(aa),理論上我們應該分類討論對吧?但實際上我們很懶,所以我們把字符串變成這樣(#a#a#)(#a#b#a#)
這樣一來,無論是什么字符串,它的長度都是奇數,只需要一種枚舉方式就可以了(奇數的枚舉方式,但同時可以枚舉的偶數的情況)
中心操作:枚舉對稱軸,有對稱軸向左右兩邊枚舉

r[i]表示以i為中點,向左右擴展回文串,所能到達的最大半徑是多少
由於我們是從右往左枚舉馬拉車,所以從0~pos的所有數的最長半徑都已經做出來了,是可用的
0~max_r就是我們已知的最大范圍

在這個基礎上,我們在pos~max_r的范圍枚舉i,並做j是關於pos的對稱軸,r[j]是已知的

接下來我們開始求關於r[i],當i+r[i]<max這個時候我們就可以用之前求過的r[j]來覆蓋i這個位置,減少了冗余計算(回文串的對稱性)

但不排除會存在i+r[i]>max_r 的情況,這個時候就不在我們的控制范圍之內了,那我們怎么辦?暴力枚舉。
在把pos轉到i的位置繼續執行上述操作
具體代碼如下
void Manacher(){ for (int i=0;t[i];++i,len+=2){ s[i<<1]='#'; if (t[i]>='A'&&t[i]<='Z') s[i<<1|1]=t[i]-'A'+'a'; else s[i<<1|1]=t[i]; } s[len++]='#'; int max_r=0,pos=0; for (int i=0;i<len;++i){ if (max_r>i) r[i]=min(max_r-i,r[2*pos-i]); else r[i]=0; while (i+r[i]+1<len&&i-r[i]-1>=0&&s[i+r[i]+1]==s[i-r[i]-1]) r[i]++; if (r[i]+i>max_r){ max_r=r[i]+i; pos=i; } } } //馬拉車
最后掃一遍r[i]求出max_r[i],max_r[i]-1就是我們要的最長回文子串的長度
