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; }