BZOJ2565 最长双回文子串 回文自动机,回文树

bzoj2565: 最长双回文串

题意

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

 

这道题可以用manacher算法解决,但是用manacher解决问题的同时,有可能需要计算长度的关系,可能会出现混乱。在这里采用更清楚的回文自动机;

在做这道题之前需要掌握的知识是回文自动机的实现和作用,如果有不了解算法的同志,请自行翻大神博客进行学习:

https://www.cnblogs.com/crazyacking/p/5234823.html

在这里,由于是要找两个回文串,还必须是相邻的,所以我们可以通过把整串翻转的方法实现求相邻回文串,根据回文树的作用,可以求出以下标i结尾的最长回文字符串,注意是以下标i结尾的最长串,而不是开始,不理解的话可以自己模拟一下字符加进回文自动机形成回文自动机的那些步骤,求出来之后可以枚举相邻的那个点来进行转移,求出最长的双回文串,这道题就结束了,现在上代码:

 

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<string>
 8 #include<queue>
 9 using namespace std;
10 const int MAXN=100005;
11 int nxt[MAXN][26],fail[MAXN],len[MAXN],num[MAXN],cnt[MAXN],mx1[MAXN],mx2[MAXN];
12 int n,m,k,l,r,last,p=0;
13 char s[MAXN],ops[MAXN];
14 inline int getfail(int x)
15 {
16     while(s[n-len[x]-1]!=s[n]) x=fail[x];
17     return x;
18 }
19 inline void add(int x,int i,int *mx)
20 {
21     last=getfail(last);
22     if(nxt[last][x]==0){
23         len[++p]=len[last]+2;
24         fail[p]=nxt[getfail(fail[last])][x];
25         nxt[last][x]=p;
26         num[p]=num[fail[p]]+1;
27     }
28     last=nxt[last][x];
29     mx[i]=len[last];
30     cnt[last]++;
31     return ;
32 }
33 int main()
34 {
35     scanf("%s",s+1);
36     m=strlen(s+1);
37     p=last=n=0;
38     len[++p]=-1;
39     fail[0]=p;
40     for(int i=1;i<=m;i++){
41         n++;
42         add(s[i]-'a',i,mx1);
43     }
44     memset(fail,0,sizeof(fail));
45     memset(cnt,0,sizeof(cnt));
46     memset(num,0,sizeof(num));
47     memset(len,0,sizeof(len));
48     memset(nxt,0,sizeof(nxt));
49     p=last=n=0;len[++p]=-1;fail[0]=p;
50     for(int i=1;i<=m;i++){
51         ops[i]=s[m-i+1];
52     }
53     for(int i=1;i<=m;i++){
54         s[i]=ops[i];
55     }
56     for(int i=1;i<=m;i++){
57         n++;
58         add(s[i]-'a',i,mx2);
59     }
60     int ans=-1;
61     for(int i=1;i<=m;i++){
62         ans=max(ans,mx1[i]+mx2[m-i+0]);
63     }
64     cout<<ans<<endl;
65     return 0;
66 } 

 

转载于:https://www.cnblogs.com/Alan-Luo/articles/9160813.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值