最长回文(Manacher)
最长回文
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12244 Accepted Submission(s): 4501
Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa
abab
Sample Output
4
3
题解:manacher算法:可以求出字符串每个位置的最长字串;
if(
mx > i)
p[i]=MIN(
p[2*id-i],
mx-i);
就是当前面比较的最远长度mx>i的时候,P[i]有一个最小值。这个算法的核心思想就在这里,为什么P数组满足这样一个性质呢?
(下面的部分为图片形式)
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<vector> #define mem(x,y) memset(x,y,sizeof(x)) using namespace std; typedef long long LL; const int INF=0x3f3f3f3f; const int MAXN=250005; int p[MAXN]; char str[MAXN],s[MAXN]; int Manacher(char *s,int len){ mem(p,0); p[0]=p[1]=1; int id=1,mx=1; int ans=0; for(int i=2;i<len;i++){ if(mx>i)p[i]=min(p[2*id-i],mx-i);//这句不加会超时,是一个优化 //找对称轴左侧这个地方和最大值地方的长度大小,找小的 else p[i]=1; while(s[i-p[i]]==s[i+p[i]])p[i]++; if(p[i]+i>mx)mx=p[i]+i,id=i;//更新对称轴id,更新右侧匹配的最大值mx ans=max(ans,p[i]); } return ans-1; } int main(){ int flot=0; while(~scanf("%s",str)){ int len=strlen(str); s[0]='@'; for(int i=0;i<len;i++){ s[2*i+1]='#'; s[2*i+2]=str[i]; } s[2*len+1]='#'; // if(flot++)puts(""); printf("%d\n",Manacher(s,2*len+2)); } return 0; }