BZOJ_2565_最长双回文串_manacher
BZOJ_2565_最长双回文串_manacher
Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
Input
一行由小写英文字母组成的字符串S。
Output
一行一个整数,表示最长双回文子串的长度。
Sample Input
baacaabbacabb
Sample Output
12
由于每个插入的'$'都对应原串中相邻的两个字符。
我们可以枚举所有的'$'然后找向左延伸的最长回文l[]和向右延伸的最长回文r[]。
manacher的时候更新单个'$'的l[]和r[]。
然后l[]从右往左,r[]从左往右推一遍。l[i]=max(l[i],l[i+2]-2) r[i]=max(r[i],r[i-2]-2)
最后求答案即可,注意答案串的左右回文串长度大于0。
代码:
#include <cstdio> #include <string.h> #include <algorithm> using namespace std; #define N 200050 char w[N]; int a[N],n,p[N],r[N],l[N]; int main() { scanf("%s",w+1); int i; n=strlen(w+1); for(i=1;i<=n;i++) a[i*2-1]='$',a[i*2]=w[i]; n=n<<1|1; a[n]='$'; int mx=0,lst,ans=0; for(i=1;i<=n;i++) { if(i<=mx) p[i]=min(p[2*lst-i],mx-i+1); else p[i]=1; while(i-p[i]>=1&&i+p[i]<=n&&a[i-p[i]]==a[i+p[i]]) p[i]++; if(mx<i+p[i]-1) mx=i+p[i]-1,lst=i; r[i-p[i]+1]=max(r[i-p[i]+1],p[i]-1); l[i+p[i]-1]=max(l[i+p[i]-1],p[i]-1); } for(i=1;i<=n;i+=2) r[i]=max(r[i],r[i-2]-2); for(i=n;i>=1;i-=2) l[i]=max(l[i],l[i+2]-2); for(i=1;i<=n;i+=2) if(l[i]&&r[i]) ans=max(ans,l[i]+r[i]); printf("%d\n",ans); }