BZOJ2342: [Shoi2011]双倍回文

【传送门:BZOJ2342


简要题意:

  给出一个字符串,求出一个最长的子串满足不但由两个回文子串组成,而且本身也是一个回文串,且这两个回文子串不重叠,并且这两个回文子串长度为偶数,也就是说原子串的长度一定是4的倍数


题解:

  之前学了Manacher,看到这道题,A了之后,忘写博客,现在补一下

  先对原字符串搞一下Manacher,然后就for一遍,枚举构成双倍回文子串的中间点,然后再用一个for来向前找左端点,同时判断是否有相应的右端点与之对应


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int p[1100000];
char s[510000],now[1100000];
int n;
int Manacher()
{
    for (int i=1;i<=n;i++) now[2*i-1]='#',now[2*i]=s[i];
    n=n*2+1;
    now[n]='#';
    int pos=0,R=0;
    for(int i=1;i<=n;i++)
    {
        int j=2*pos-i;
        if(i<=R) p[i]=min(p[j],R-i);
        else p[i]=1;
        while(1<=i-p[i]&&i+p[i]<=n&&now[i-p[i]]==now[i+p[i]]) p[i]++;
        if(i+p[i]>R){pos=i;R=i+p[i];}
    }
}
int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    Manacher();
    int ans=0;
    for(int i=1;i<=n;i+=2) 
    {
        if(p[i]%2==0||ans>=p[i]-1) continue;
        for(int j=i-(p[i]-1)/2;j<i;j++)
        {
            if((i-j)*2<=ans) break;
            if((i-j)%2!=0) continue;
            if(j+p[j]-1>=i){ans=max(ans,(i-j)*2);break;}
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-11-22 13:15  Star_Feel  阅读(162)  评论(0编辑  收藏  举报