题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

baacaabbacabb
输出样例#1:

12

说明

【样例说明】

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

对于100%的数据, 2≤∣S∣≤105

Solution:

  本题$zyys$啊!~

  很容易想到$manacher$,于是先打个板子看看,处理出以$i$为中心的最长回文半径$p[i]$后,就断思路了。

  我首先想到的是,在每次更新$p[i]$后,分别处理出以$i$为中心的半径$p[i]$内,每个位置为开头和结尾的最长回文子串长度($manacher$结束后直接枚举断点就可以得到答案),但是这样强行又将复杂度拉到了$O(n^2)$。于是,开始断线~

  后面看看巨佬们的思路,豁然**,我是真的蠢啊~

  其实,将我开始的思路修改一下即可:

  我们维护最长回文半径$p[i]$的同时,再分别维护两个东西,以$i$为结尾的最长回文子串的长度$ll[i]$,和以$i$为开头的最长回文子串的长度$rr[i]$。

  那么很显然,因为以$i$为中心的最长回文子串长度为$p[i]-1$,所以每次更新$p[i]$后,我们只需处理出当前这个回文子串的左右边界(中间的每个点的$ll[i],rr[i]$可以在$manacher$结束后$O(n)$处理出),则$ll[i+p[i]-1]=max(ll[i+p[i]-1],p[i]-1)$(更新以$i+p[i]-1$为结尾的最长回文长度),同理$rr[i-p[i]+1]=max(rr[i-p[i]+1],p[i]-1)$。

  跑完$manacher$后,我们$O(n)$递推出每个$#$为断点的$ll[i]$和$rr[i]$,其中$rr[i]$因为是$i$结尾的回文长度,所以直接顺推,每往后移一位,最长回文子串长度$-2$,于是$rr[i]=max(rr[i],rr[i-2]-2)$($i-2$是上一个$#$位置),同理$ll[i]$直接逆推,类似地$ll[i]=max(ll[i],ll[i+2]-2)$。

  最后枚举每个$#$为断点,更新$ans$就$OK$了。

代码:

#include<bits/stdc++.h>
#define For(i,a,b,c) for(int (i)=(a);(i)<=(b);(i)+=(c))
#define Bor(i,a,b,c) for(int (i)=(b);(i)>=(a);(i)-=(c))
#define Min(a,b) ((a)>(b)?(b):(a))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=;
int p[N],ll[N],ans,rr[N],mx,id,cnt;
char s[N],t[N];
int main(){
scanf("%s",t);
int len=strlen(t);
s[++cnt]='$',s[++cnt]='#';
For(i,,len-,)s[++cnt]=t[i],s[++cnt]='#';
s[++cnt]='\0';
For(i,,cnt,){
if(i<mx)p[i]=Min(p[id*-i],mx-i);
else p[i]=;
while(s[i-p[i]]==s[i+p[i]])p[i]++;
if(mx<i+p[i])id=i,mx=i+p[i];
ll[i+p[i]-]=Max(ll[i+p[i]-],p[i]-);
rr[i-p[i]+]=Max(rr[i-p[i]+],p[i]-);
}
For(i,,cnt,)rr[i]=Max(rr[i],rr[i-]-);
Bor(i,,cnt,)ll[i]=Max(ll[i],ll[i+]-);
For(i,,cnt,)if(rr[i]&&ll[i])ans=Max(ans,ll[i]+rr[i]);
cout<<ans;
return ;
}

最新文章

  1. hiho一下 第六十六周
  2. mac 隐藏、显示文件
  3. oracle SGA详解
  4. reactjs入门到实战(六)---- ReactJS组件API详解
  5. EasyUI扩展方法
  6. mysql 连接命令 表管理 ,克隆表,临时表,字符串属性,设定语句间的分隔符
  7. linux常用命令收集(持续中)
  8. linux修改rm指令执行(数据安全)
  9. AES加密解密 助手类 CBC加密模式
  10. VCenter6.0.0的安装过程
  11. jdbc工具类2..0
  12. java运算符-算数、赋值、比较
  13. DevOps: CLM, RLM, RPM, RPD, BSA, BAA, BMA - WOW!
  14. redis epoll 原理梗概
  15. MySQL基本操作命令
  16. Appium-desktop的下载&amp;安装
  17. hive orc update
  18. jdk8-lambda表达式的使用
  19. 【RDB】MariaDB 之事务、复制、集群
  20. HTML/css之弹性布局

热门文章

  1. 2018.2.6 JS-判断用户浏览器
  2. 分词,复旦nlp,NLPIR汉语分词系统
  3. CSVDE
  4. axiospost请求向后端提交数据
  5. {&quot;errmsg&quot;:&quot;invalid weapp pagepath hint: [IunP8a07243949]&quot;,&quot;errcode&quot;:40165}微信的坑
  6. Oracle 字符串处理函数
  7. 搭建mock服务器(微信小程序)
  8. P4746 C’s problem(c)
  9. 【解题报告】AtCoder ABC115 (附英文题目)
  10. kali下将Python2.x切换至Python3.x