p4555&bzoj2565 最长双回文串

传送门(洛谷)

传送门(bzoj)

题目

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

输入长度为 nnn 的串 SSS ,求 SSS 的最长双回文子串 TTT ,即可将 TTT 分为两部分 XXX , YYY ,( ∣X∣,∣Y∣≥1|X|,|Y|≥1X,Y1 )且 XXX 和 YYY 都是回文串。

输入格式:

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

输出格式:

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

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

分析

运用manacher算法,在找以i为中心的最长回文串的同时不断更新此串所覆盖点的str和end,即以某点为第一个点的最长回文串长度和以某点为最后一个点的最长回文串长度,最后某点的双回文串的长度有两种情况:

   1.如果该字符是后加的‘$’则长度为str[i]+end[i]

   2.如果该字符原本就存在则长度为str[i]+end[i]-1

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int len1,len2;
char s1[310000],s2[310000];
int end[310000],str[310000],p[310000];
void init(){
      s2[0]='#';
      s2[1]='$';
      for(int i=0;i<len1;i++){
           s2[i*2+2]=s1[i];
           s2[i*2+3]='$';
      }
      len2=len1*2+2;
      s2[len2]='@';
}
void horsewithcar(){
      int maxn=0,id=0;
      for(int i=1;i<len2;i++){
           if(maxn>i)p[i]=min(p[id*2-i],maxn-i);
             else p[i]=1;
           for(;s2[i+p[i]]==s2[i-p[i]];p[i]++){
              if(i+p[i]>maxn){
                  maxn=i+p[i];
                  id=i;
              }
              str[i-p[i]]=max(str[i-p[i]],p[i]);
              end[i+p[i]]=max(end[i+p[i]],p[i]);
           }
      }
}
int main()
{     int n,m,i,j,k;
      scanf("%s",s1);
      len1=strlen(s1);
      init();
      horsewithcar();
      int maxn=0;
      for(i=1;i<=len2;i++)
         if(s2[i]=='$')maxn=max(maxn,str[i]+end[i]);
           else maxn=max(maxn,str[i]+end[i]-1);
      cout<<maxn<<endl;
      return 0;
}

posted @ 2018-05-15 10:00  水题收割者  阅读(167)  评论(0编辑  收藏  举报