Problem Description
给出一个只由小写英文字符a,b,c…y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c…y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa
abab
Sample Output
4
3
算法简介
首先manachar是一个O(N)的算法,它的作用是判断一个字符串的最长回文子串
在每两个字符以及字符串的头和尾中加一个奇怪的字符,一般我们选用#
我们设p[i]为以i这个位置为回文的中心,可以获得半径为p[i]的回文串
它的优点
1:相信大家做回文串的时候对一件事情都会感到特别烦:回文可能是偶数的也可能是奇数的,一般的做法中我们需要分开处理这两种情况,但是manachar运用了一个巧妙的方法(在每两个字符以及字符串的头和尾中加一个奇怪的字符,一般我们选用#),这样我们就可以同时处理出奇数个数和偶数个数长度的回文串了
2:我们可以发现,对于以i为中心的最长回文串,它的长度就是p[i]-1(这里面有很多种情况,分类讨论后可以发现这一规律,不再赘述),所以我们只要求出p[i]就好了
算法实现
首先我们找出在以[1..i]中一个位置为中心,可以向右到最远位置的那个位置,我们设它为id,而当前到过的最远的位置为mx
那么现在有两种情况
1:i>=mx 此时p[i]的最小值显然为1
2:i
<
<script type="math/tex" id="MathJax-Element-170"><</script>mx 那么我们发现有s[2*id-i]=s[i] (2 *id-i,i关于id对称)而且都在以id为中心的回文串内
那么根据回文串的定义,我们似乎可以得到p[i]的最小值为p[2*id-i],因为对称性的关系
但是如果i+p[2*id-i]>mx呢?这已经超出当前找过的最远位置了,显然我们不知道后面这些位置是否能和前面匹配
所以p[i]:=min(p[2*id-i],mx-i)
然后我们在这个最小值的基础上往后面扩展
显然每次扩展必定导致mx+1
所以这个算法是O(N)的
在字符串的第一位可以加入另外一个奇怪的字符,防止越界
注意数组范围要开两倍再多一点
贴代码
var
s:array[0..230005]of char;
p:array[0..230005]of longint;
i,j,k,l,m,n,id,mx,ans:longint;
ch:char;
function min(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
begin
//assign(input,'hdu_3068.in'); reset(input);
while not eof do
begin
n:=2;
s[1]:='!';
s[2]:='#';
while not eoln do
begin
read(ch);
inc(n);
s[n]:=ch;
inc(n);
s[n]:='#';
end;
readln;
id:=0;
mx:=0;
ans:=0;
for i:=1 to n do
begin
if i<mx then p[i]:=min(p[2*id-i],mx-i) else
p[i]:=1;
while (s[i+p[i]]=s[i-p[i]]) do inc(p[i]);
if p[i]>ans then ans:=p[i];
if i+p[i]>mx then
begin
id:=i;
mx:=i+p[i];
end;
end;
readln;
writeln(ans-1);
end;
// close(input);
end.