51nod(1089 最长回文子串 V2)(hash 加二分)

1089 最长回文子串 V2(Manacher算法)

 
回文串是指aba、abba、cccbccc、aaaa这种左右对称的字符串。
输入一个字符串Str,输出Str里最长回文子串的长度。
 

输入

输入Str(Str的长度 <= 100000)

输出

输出最长回文子串的长度L。

输入样例

daabaac

输出样例

5


虽然题目要求用Manacher算法,但由于算法进阶指南上有一种hash解法,我就照着思路敲了一边代码,大概就是用O(N)
的时间处理字符串和他反向后字符串的hash值,然后再用二分判断,枚举长度,复杂度logn,总体复杂度nlogn。代码如下
#include<bits/stdc++.h>
using namespace std;
char s[100005];
unsigned long long a[100005];
unsigned long long b[100005];
unsigned long long p[100005];
int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1),maxn=0;
    p[0]=1;     
    for(int i=1;i<=n;i++)
    {
        a[i]=(a[i-1]*59+(s[i]-'A'+1));
        p[i]=(p[i-1]*59);
    }
    for(int i=1;i<=n;i++)
    {
        b[i]=b[i-1]*59+(s[n-i+1]-'A'+1);
    }
    for(int i=1;i<=n;i++)
    {
        if(s[i-1]==s[i+1])
        {
        int r=min(i-1,n-i);
        int l=1;
        int mid=(l+r)/2;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(b[n-i]-b[n-i-mid]*p[mid]==a[i-1]-a[i-mid-1]*p[mid])
            {
                l=mid+1;
            }
            else
            {
                r=mid-1;
            }
         }
         maxn=max(maxn,(l-1)*2+1); 
    }
    if(s[i]==s[i+1])
    {
        int r=min(i,n-i+1);
        int l=1,mid=(l+r)/2;
        while(l<=r)
        {
            mid=(l+r)/2;
            if((b[n-i]-b[n-i-mid]*p[mid])==(a[i]-a[i-mid]*p[mid]))
            {
                l=mid+1;
            }
            else
            {
                r=mid-1;
            }
         }
         maxn=max(maxn,(l-1)*2); 
    }
    }
    cout<<maxn<<"\n";
    return 0;
}

 

 
posted @ 2019-06-24 12:48  hh13579  阅读(341)  评论(0编辑  收藏  举报