Lflame

Manacher !!!

    Manacher的算法过程就不细讲了,这个很简单。

    

    注意一点性质 : 一个串本质不同的回文子串个数为O(N)个。

    因为只有在mx(最右的能延伸到的点)向右扩展时,才会产生新的回文子串,否则一定在对称的位置出现过。

    这样的话,我们便可以找出所有本质不同的回文子串。    

    

    然后说一说实现。

    众所周知的,Manacher之烂大街实现方法 --- 相邻点间加上符号'#',首尾加上不同的特殊符号,这样便可将奇偶结合起来。


    我的代码:

void manacher(){ //没有写插入特殊字符

int mx=0 , id;

for(int i=1;i<=m;++i){  //m为添加字符后的串长

if(mx>=i) pal[i]=min(mx-i+1,pal[2*id-i]) ;

else pal[i]=1 ;

while(s[i-pal[i]]==s[i+pal[i]]) ++pal[i] ;

if(i+pal[i]-1>mx) {

mx=i+pal[i]-1 , id=i ;

}

}

}



    如下(代码粘自黄学长):

    (update:该代码不太好,可以看自己之前的代码)

void manacher()

{

m=2*n+1;

for(int i=1;i<=n;i++)                       //添加特殊字符

{

a[i<<1]=ch[i];

a[i<<1|1]='#';

}

a[0]='+';a[1]='#';a[m+1]='-';

int mx=0,id;

for(int i=1;i<=m;i++)                   //主过程

{

if(mx>i)p[i]=min(mx-i,p[2*id-i]);

else p[i]=1;                                  //这一步可能找到新回文串

for(;a[i-p[i]]==a[i+p[i]];p[i]++);  //还有这一步,因为一旦扩展,mx也会扩展

if(p[i]+i>mx)mx=p[i]+i,id=i;

}

}


      但是 !!  这对于有些题来说会特别烦 ! 对于这些题,我们便可以直接分奇偶回文,做两遍即可。

       如下(代码仍然粘自黄学长):

       

void manacher()

{

int mx=0,id;

for(int i=1;i<=n;i++)

{

if(mx>i)p[i]=min(mx-i,p[2*id-i-1]);

else p[i]=0;

while(ch[i+p[i]+1]==ch[i-p[i]])

{

p[i]++;

}

if(p[i]+i>mx)mx=p[i]+i,id=i;

}

mx=0;

for(int i=1;i<=n;i++)

{

if(mx>i)p[i]=min(mx-i-1,p[2*id-i]);

else {p[i]=1;}

while(ch[i+p[i]]==ch[i-p[i]])

{

p[i]++;

}

if(p[i]+i>mx)mx=p[i]+i,id=i;

}

}

评论