HDU3068-manacher演算法-最長迴文串
阿新 • • 發佈:2018-12-24
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;
}