bzoj2565(manachery)

2565: 最长双回文串

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1083   Solved: 582
[ Submit][ Status][ Discuss]

Description

顺序和逆序读起来完全一样的串叫做回文串。比如 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

HINT

样例说明

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

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


2015.4.25新加数据一组


解题思路:

  首先进行Manachery,然后枚举“#”为中心点,找到前面可以到达它的最长点,以及后面可以到达它的最长点,最后再枚举判断就行了,可以用单调队列来维护。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
char s[300001];
char c[300001];
int lg[300001];
int q[300001];
int ma1[300001];
int ma[300001];
int len,len_now;




int Init()
 {
  c[1]='@';
  for (int i=1;i<=len;++i)
  {
  c[i*2]=s[i];
  c[i*2+1]='#';
 }
c[2*len+1]='$';
return 2*len+1;
 }


void manachery()
 {
  int mx=0; int po=0; 
  for (int i=1;i<=len_now;++i)
  {
  if (mx>i)
  lg[i]=min(mx-i,lg[2*po-i]);else lg[i]=1;
  while (c[i+lg[i]]==c[i-lg[i]]){++lg[i];}
     if (lg[i]+i-1>mx)
      {
      mx=lg[i]+i-1;
      po=i;
 }
 }
 }


int main()
  {
  cin>>s+1; 
len=strlen(s+1);
  memset(lg,0,sizeof(lg));
  len_now=Init();
  manachery();
  int tail=0; int head=0;
    for (int i=1;i<=len_now;i+=1)
     {
      while (head<tail && q[head+1]+lg[q[head+1]]-1<i-1)++head;
        ++tail; q[tail]=i; 
ma[i]=q[head+1];
}
tail=0; head=0;
for (int i=len_now;i>=1;i-=1)
{
while (head<tail && (q[head+1]-lg[q[head+1]]+1>i+1)) ++head;
++tail; q[tail]=i;
ma1[i]=q[head+1];
}
int ans=2;
for (int i=3;i<=len_now;i+=2)
{
  if (i-ma[i]+ma1[i]-i>ans)
   ans=i-ma[i]+ma1[i]-i;
}
cout<<ans;
  }

你可能感兴趣的:(bzoj2565(manachery))