hdu-3068-最长回文(manacher)

 

好的讲解manacher算法的文章,图文并茂。

http://blog.csdn.net/ggggiqnypgjg/article/details/6645824

题解来源:http://blog.sina.com.cn/s/blog_6fa65cf90100s3sg.html

题意:求给定串的最长回文子串(2009多校题目)

分析:

枚举每个点向左向右扩展,看最远能扩展到哪儿.但是普通的枚举是n^2的,肯定超时。现在我们想kmp或扩展kmp一样,给字符串定义一个nex数组,nex[i]表示以i为中心最远能向右扩展的长度,使得s[i – nex[i] + 1……. i + nex[i]- 1]形成的回文。然后我们利用这个数组,在O(n)的时间内求出每个inex[i]。在其他算法中,奇数回文和偶数回文经常给我们带来麻烦,这个算法中,我们第一步要进行的是将每个字符后边(包括开头)加入一个字符(不在串儿的字符集中就行),一般用’#”. 这样就都转换为了奇数的情况。

例如       abba  (偶)

         改为   #a#b#b#a# (最长为以第3#为中心)

             aba    (奇) 

改为    #a#b#a#  (最长为以b为中心)      

剩下的就是在我们知道了nex[0]…….nex[i – 1] 如何求nex[i] p记录前i-1个字符中以某个字符id为中心最远能向右扩展到的位置。

// File Name: 3068.cpp
// Author: Zlbing
// Created Time: 2013/5/9 13:30:20

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
const int maxn=2e5;
char str[maxn],str1[maxn*2];
int n,ans,nxt[maxn*2];
void Manacher()
{
    memset(nxt,0,sizeof(nxt));
    int mx=0,id;
    for(int i=1;i<n;i++)
    {
        if(mx>i)
            nxt[i]=min(nxt[2*id-i],mx-i);
        else nxt[i]=1;
        for(;str1[i-nxt[i]]==str1[i+nxt[i]];nxt[i]++);
        if(i+nxt[i]>mx)
        {
            mx=i+nxt[i];
            id=i;
        }
    }
}
void pre()
{
    int i=0,k=1,t=0;
    str1[0]='$';
    while(str[i]!='\0')
    {
        str1[k++]=t?str[i++]:'#';
        t^=1;
    }
    str1[k++]='#';
    str1[k]='\0';
    n=k;
}
int main()
{
    while(scanf("%s",str)==1)
    {
        pre();
        Manacher();
        int maxx=0;
        for(int i=0;i<n;i++)
            if(maxx<nxt[i]-1)
                maxx=nxt[i]-1;
        printf("%d\n",maxx);
    }
    return 0;
}

 

posted @ 2013-05-09 13:34  z.arbitrary  阅读(188)  评论(0编辑  收藏  举报