BZOJ 2565 最长双回文串 Manacher

BZOJ 2565 最长双回文串 Manacher


题目

顺序和逆序读起来完全一样的串叫做回文串。比如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的过程中求出一些很有用的东西,下文将会予以论述,而我要是和Manacher一起求出来的话那么感觉就会非常的好

就是,这道题其实非常的水,我们只要先Manacher一下,然后求出一个位置的左边的右端点为这个字符的最长回文串的长度,不妨存入 Left 数组,右侧同理,存入 Right 数组,然后我们求 Ans=max(Ans,Left[i]+Right[i+1]),i(0,len1) 即可

代码

让注释记录我思维无力的挣扎

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 100005
using namespace std;
int f[maxn*2],len1,pre[maxn*2],suf[maxn*2],len;
char txt[maxn],s[maxn*2];
void Manacher(){
    for(int i=0;i<len1;i++){
        s[i<<1]='@';
        s[(i<<1)+1]=txt[i];
    }
    s[(len1)<<1]='@';
    len=2*len1+1;
    int mx=0,p=0;
    for(int i=0;i<len;i++){
        if(mx>i) f[i]=min(mx-i,f[2*p-i]);
        else f[i]=0;
        while(i+f[i]+1<len&&i-f[i]-1>=0&&s[i+f[i]+1]==s[i-f[i]-1]) f[i]++;
        if(f[i]+i>mx){
            mx=f[i]+i;
            p=i;
        }
    }
    return;
}
void process(){
    for(int i=0;i<len;i++){
        if(i&1){
            f[i]=((f[i]>>1)<<1)+1;
        }else{
            f[i]=((f[i]+1)>>1)<<1;
        }
    }
    int now=-1;
    for(int i=1;i<len-1;i++){
        if(i&1){
            if((i>>1)>now){
                pre[++now]=1;
            }
            while(((i>>1)+(f[i]>>1))>now){
                now++;
                pre[now]=((now-(i>>1))<<1)+1;
            }
        }
        else{
            if((i>>1)>now){
                pre[++now]=1;
            }
            while(((i>>1)+(f[i]>>1)-1)>now){
                now++;
                pre[now]=(now-(i>>1)+1)<<1;
            }
        }
    }
    now=len1;
    for(int i=len-2;i>0;i--){
        if(i&1){
            if((i>>1)<now){
                suf[--now]=1;
            }
            while(((i>>1)-(f[i]>>1))<now){
                now--;
                suf[now]=(((i>>1)-now)<<1)+1;
            }
        }
        else{
            if((i>>1)<now){
                suf[--now]=1;
            }
            while(((i>>1)-(f[i]>>1))<now){
                now--;
                suf[now]=(-now+(i>>1))<<1;
            }
        }
    }
    /*int now=0;
    for(int i=0;i<len1;i++){
        if(f[2*i]-1+i>f[2*i+1]+i){
            while(f[2*i]-1+i>now){
                pre[now]=((now-i)<<1)+1;
                now++;
            }
        }
        else{
            while(f[2*i+1]+i>now){
                pre[now]=(now-i)<<1;
                now++;
            }
        }
    }
    pre[0]=1;
    now=len1-1;
    for(int i=len1-1;i>=0;i--){
        if(i-f[2*i]+1<i-f[2*i+1]+1){
            while(i-f[2*i]+1<now){
                suf[now]=((i-now)<<1)+1;
                now--;
            }
        }
        else{
            while(i-f[2*i+1]+1<now){
                suf[now]=(i-now+1)<<1;
                now--;
            }
        }
    }
    suf[len-1]=1;
    int ans=0;
    for(int i=0;i<len1;i++){
        ans=max(ans,pre[i]+suf[i+1]);
    }
    printf("%d",ans);
    return;*/
    /*int now=0;
    for(int i=0;i<len;i++){
        while(i+f[i]>now){
            if(i>=now){
                pre[now]=1;
                now++;
                continue;
            }
            if(!(i&1))pre[now]=(((now-i)>>1)<<1)+1;
            else pre[now]=(((now-i+1)>>1)<<1);
            now++;
        }
    }
    now=len-1;
    for(int i=len-1;i>=0;i--){
        while(i-f[i]<now){
            if(i<=now){
                suf[now]=1;
                now--;
                continue;
            }
            if(!(i&1))suf[now]=(((i-now)>>1)<<1)+1;
            else suf[now]=(((i-now+1)>>1)<<1);
            now--;
        }
    }
    suf[0]=1;*/
    /*int now=0;
    for(int i=0;i<len;i++){
        while(i+f[i]>now){
            now++;
            pre[now]=((now-i)<<1)+1;
        }
    }
    for(int i=0;i<len;i++){
        if(!(i&1))pre[i]>>=1;
        else pre[i]=(pre[i]+1)>>1;
    }
    now=len-1;
    for(int i=len-1;i>=0;i--){
        while(i-f[i]<now){
            now--;
            suf[now]=((i-now)<<1)+1;
        }
    }
    for(int i=len-1;i>=0;i--){
        if(!(i&1))suf[i]>>=1;
        else suf[i]=(suf[i]+1)>>1;
    }*/
    int ans=0;
    for(int i=0;i<len1-1;i++){
        ans=max(ans,pre[i]+suf[i+1]);
    }
    printf("%d",ans);
    return;
}
int main(){
    /*freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);*/
    scanf("%s",txt);
    len1=strlen(txt);
    Manacher();
    process();
    return 0;
}

细节

我实在不知道怎么说,满屏的细节QAQ

总结

要灵活地运用Manacher算法
我真是太弱了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值