zoukankan      html  css  js  c++  java
  • P4555 [国家集训队]最长双回文串(回文树)

    题目描述

    顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同)。

    输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y都是回文串。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制

    baacaabbacabb

    输出样例#1: 复制

    12

    说明

    【样例说明】

    从第二个字符开始的字符串aacaabbacabb可分为aacaabbacabb两部分,且两者都是回文串。

    对于100%的数据, 2≤|S|≤10^5


    题解

    直接顺序回文树统计一遍每一位结尾的回文串的长度
    再倒序统计一遍
    最后暴力遍历一遍统计的结果就好了。


    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    struct node{
        int len,ch[26],fail;
    }t[100001];
    int f[100001],g[100001],tot;
    char s[100001];
    int read()
    {
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    void solve1()
    {
        int len=strlen(s+1),k=0;s[0]='$';
        t[0].fail=1;t[1].len=-1;tot=1;
        for(int i=1;i<=len;i++)
        {	
            while(s[i-t[k].len-1]!=s[i])k=t[k].fail;
            if(!t[k].ch[s[i]-'a']){
                t[++tot].len=t[k].len+2;
                int j=t[k].fail;
                while(s[i-t[j].len-1]!=s[i])j=t[j].fail;
                t[tot].fail=t[j].ch[s[i]-'a'];
                t[k].ch[s[i]-'a']=tot;
            }
            k=t[k].ch[s[i]-'a'];
            f[i]=t[k].len;
        }
    }
    
    void solve2()
    {
        int len=strlen(s+1),k=0;s[0]='$';
        t[0].fail=1;t[1].len=-1;tot=1;
        for(int i=1;i<=len;i++)
        {
            while(s[i-t[k].len-1]!=s[i])k=t[k].fail;
            if(!t[k].ch[s[i]-'a']){
            t[++tot].len=t[k].len+2;
            int j=t[k].fail;
            while(s[i-t[j].len-1]!=s[i])j=t[j].fail;
            t[tot].fail=t[j].ch[s[i]-'a'];
            t[k].ch[s[i]-'a']=tot;
            }
            k=t[k].ch[s[i]-'a'];
            g[len-i+1]=t[k].len;
        }
    }
    
    int main()
    {
        scanf("%s",s+1);
        int len=strlen(s+1);
        solve1();
        reverse(s+1,s+len+1);
        memset(t,0,sizeof(t));
        solve2();
        int ans=0;
        for(int i=1;i<len;i++)ans=max(ans,f[i]+g[i+1]);
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    第五周作业
    作业4
    20182302 2019-2020-1 《数据结构与面向对象程序设计》实验3报告
    作业四
    实验二
    实验一
    排序大集合java
    阿里面试——运筹优化工程师
    树的子结构判断
    剑指offer——合并两个排序的链表——对象、引用和赋值初接触
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9246011.html
Copyright © 2011-2022 走看看