BZOJ 2565 Manacher 解题报告

来源:互联网 发布:超级sql注入工具教程 编辑:程序博客网 时间:2024/06/06 06:55

2565: 最长双回文串

Description

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。

Input

一行由小写英文字母组成的字符串S。

Output

一行一个整数,表示最长双回文子串的长度。

Sample Input

baacaabbacabb

Sample Output

12

【解题报告】
首先可以相当manacher算法当中有这样一个过程, 用两个辅助变量mx和p分别表示已有回文半径覆盖到的最右边界和对应中心的位置, 然后在求解过程中更新mx和p, 考虑到S和T的中间字符作为分隔的位置, 当这个位置被mx覆盖之后, mx从左往右更新第一次覆盖的时候p(覆盖它的串的中心)的位置一定是离这个位置最远的也就是找到了S的中心, 由于mx移动距离至多为n, 所以随着manacher算法的进行用dp来记录mx被更新时的那个回文串的信息即可, 找到S中心之后, 类似的反向从右往左做一遍manacher然后找到T的中心
这样O(n)的预处理之后找出了每个分隔符之下S和T的中心的最佳位置, 最后枚举一下分隔符的位置即可找到最优解
总体时间复杂度O(n)

代码如下:

/**************************************************************    Problem: 2565    User: onepointo    Language: C++    Result: Accepted    Time:80 ms    Memory:14492 kb****************************************************************/#include<cstdio>#include<cstring>#include<algorithm> using namespace std;#define N 1000010char s1[N],str[N];int n,len,rl[N],mx,pos,ls[N],rs[N],ans;int main(){    scanf("%s",s1);    int i,j,a;    len=strlen(s1);    for(i=0;i<len;i++) str[n++]='*',str[n++]=s1[i];    str[n++]='*';    for(mx=-1,i=0;i<n;i++)    {        if(mx>i) rl[i]=min(mx-i+1,rl[2*pos-i]);        else rl[i]=1;        for(;i+rl[i]<n&&rl[i]<=i&&str[i+rl[i]]==str[i-rl[i]];rl[i]++);        if(i+rl[i]-1>mx) mx=i+rl[i]-1,pos=i;        rs[i-rl[i]+1]=max(rs[i-rl[i]+1],rl[i]-1);        ls[i+rl[i]-1]=max(ls[i+rl[i]-1],rl[i]-1);    }    for(i=0;i<n;i+=2) rs[i]=max(rs[i],rs[i-2]-2);    for(i=n-1;i>=0;i-=2) ls[i]=max(ls[i],ls[i+2]-2);    for(i=0;i<n;i+=2) ans=max(ans,ls[i]+rs[i]);    printf("%d",ans);    return 0;}
原创粉丝点击