[BZOJ2565] 最长双回文串
题目大意:求最长的连续的两个回文串的长度
题解:Manacher+枚举
首先知道两个连续回文串的中间的那个字符一定是‘#’。
然后枚举‘#’。看以这个字符为中心,左右最长的回文串
有多长。
now+Len[now]>i时,那么以now为中心的回文串是在i左边
的,尽管超出了i,可以左右砍掉嘛//。i-now就是i左边的回文
串的长度。一开始不太明白i-now为什么是,因为还有'#'啊,写了
几个符号i-now就是左边回文串的长度。
ps:如果有哪位dalao看到这篇题解,可以告诉我更好的理解方法吗?orz
代码:
#include<iostream> #include<cstdio> #include<cstring> #define maxn 100009 using namespace std; int len,now,ans; char s[maxn*2],str[maxn*2]; int Len[maxn*2],l[maxn*2],r[maxn*2]; void getstr(){ int k=0;str[0]='$'; for(int i=0;i<len;i++){ str[++k]='#';str[++k]=s[i]; } str[++k]='#';len=k; } void Manacher(){ int mx=0,id;getstr(); for(int i=1;i<=len;i++){ if(mx>i)Len[i]=min(mx-i,Len[2*id-i]); else Len[i]=1; while(str[i+Len[i]]==str[i-Len[i]])Len[i]++; if(i+Len[i]>mx)mx=i+Len[i],id=i; } } int main(){ scanf("%s",&s);len=strlen(s); Manacher(); for(int i=1;i<=len;i++){ if(str[i]=='#'){ while(now+Len[now]<i)now++; l[i]=i-now; } }now=len; for(int i=len;i>=1;i--){ if(str[i]=='#'){ while(now-Len[now]>i)--now; r[i]=now-i; } } for(int i=1;i<=len;i++)ans=max(ans,l[i]+r[i]); cout<<ans<<endl; return 0; }