1. 程式人生 > >HDU3068-manacher演算法-最長迴文串

HDU3068-manacher演算法-最長迴文串

https://vjudge.net/problem/HDU-3068
求最長的迴文串。
有一次用dp求過一次。
:我們都知道求迴文串可以依賴於暴力的方法(以某點為重心,暴力的比唄),manacher方法的思想在於利用對稱性來減少暴力運算,從而提高效率。
從左到右遍歷字元,記錄最大的 迴文串的右界(記當時的 字元位置為i)
分兩種情況 1 當前遍歷字元x在 右界右邊。這時候無法利用對稱性,只能一個一個算了。qwq 對應圖第一個
2 單前字元 在字元右界左邊,hiahia 這下就可以利用了qwq
① x以i對稱的點的 迴文串 完全被包括在 最大回文串中,由於對稱性說明當前的點的 迴文串也被完全包括,無法拓展(如果可以拓展的話,那麼左邊也可以拓展,但是左邊已經計算過了,所以不能拓展) ,對應圖第二個 為 dp[id*2-i](id*2-i意思就是id對稱的i的位置)
② x以i對稱的點 的迴文串 的左界 小於 最長迴文串的左界(更左),這時候的長度 為 dp[id]+id-i(根據對稱性計算) ,為 綠色靠左那一部分。
③ 對稱點的左界和最大左界相等, 這時候可能 會增加。
這裡寫圖片描述


具體見程式碼

#include <bits/stdc++.h>
using namespace std;
/* manacher
  求最長迴文串,暴力操作。
 就是利用對稱性,來減少這種操作。
  記錄 最長的能夠到達的位置。
  同時定義了三種情況。
    不願意看到的情況  ,暴力查詢。
   2 願意看到的情況
   分三種情況 
*/
int main()
{   char  s[110006];
    int p[2*110006+1000];
    char b[2*110006+1000];
    while(~scanf("%s",s)){
         //下面,是構造‘我們需要的串’的過程
memset(p,0,sizeof(p)); b[0]='*'; int t=1; int len=strlen(s); for(int i=0;i<len;i++){ b[t++]='#'; b[t++]=s[i]; } b[t]='#'; int zz=0,rig_max=0; int max1=0; for(int i=2;i<t;i++){ if
(zz+p[zz]>i) //包含在裡面了 { p[i]=min(p[zz*2-i],p[zz]-i+zz); while(b[i+p[i]]==b[i-p[i]]) p[i]++;//延伸 } else{ p[i]=1; int j=1; while((i>=j)&&b[i+j]==b[i-j]) p[i]++,j++; } if(p[i]+i>p[zz]+zz){ zz=i; } if(p[i]>max1) max1=p[i]; } printf("%d\n",max1-1); } return 0; }