Manacher学习笔记
马拉车(Manacher)算法其实蛮简单的,我看了两眼居然就会了.............,早知道以前多看一眼
算法的核心在于先预处理字符串,将所有回文转化为奇回文讨论,然后在暴力枚举回文中心时,利用回文的对称性,快速计算回文半径,去掉一些不必要的比较,从而使得复杂度下降至O(n)
举个比较简单例子,假设你是从左到右,且i,k关于j对称,且i<j<k,以j为中心的最长回文范围是[Li,Rj]。则如果k内[Li,Rj],不妨令d=Rj-k。因为[Li,Rj]是回文,所以[k-d,Rj] 与[Li,i+d]的部分是一模一样,可以通过查询已经计算过的i的回文半径,来直接确定[k-d,Rj] 这部分回文情况,从而省掉大量冗余的比较。
具体的详细的讲解可以看,这篇博客https://blog.csdn.net/the_star_is_at/article/details/53354958
我代码实现如下:
简单习题 HDU3068,POJ3974 都是模板题
我的代码实现如下:
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #include<vector> #include<stack> using namespace std; char ss[2000005]; void init() { memset(ss,'#',sizeof(ss)); ss[0]=1; } int p[2000005]; int manacher(char str[]) { int i; for(i=0;str[i];i++) { ss[i+i+2]=str[i]; } ss[i+i+2]=0; int len=i+i,mx=0,id=0,ans=1; // puts(ss+1); for(i=1;i<=len;i++) { p[i]=1; if(i<mx) p[i]=min(mx-i+1,p[2*id-i]); if(p[i]+i>mx) { id=i; while(ss[i+p[i]]==ss[i-p[i]]) { p[i]++; } mx=i+p[i]-1; } // printf("%d\n",p[i]); if(ss[i]=='#') ans=max(ans,p[i]/2*2); else { ans=max(ans,(p[i]-1)/2*2+1); } } return ans; } char s[1000005]; int main() { int i,j,t,n,x,y,k,m,cas=1; init(); while(scanf("%s",s)!=EOF) { if(strcmp(s,"END")==0) break; printf("Case %d: %d\n",cas++,manacher(s)); } return 0; }