最长回文
http://cdqz.openjudge.cn/noip/1029/
描述:
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
输入:
一个文件一组数据
每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
字符串长度len <= 110000
输出:
一个整数x,表示该字符串中所包含的最长回文长度.
样例输入
aaaa
-------------
abab
样例输出
4
-------------
3
Source
HDU - 3068
Hint
扩展HDU 3948 The Number of Palindromes
题解:
Manacher的模板题。
Manacher是一种很有想象力的在O(n)的复杂度内实现的求最长回文子串长度的算法。主要代码很短,不到20行。首先这种算法只能处理奇数长度的字符串,于是为了解决这个问题,我们采取在字符串中加美元或者加各种奇葩字符来解决。另外,我们用数组p[i]来记以i为中心向右数最大的回文长度,于是我们得到如下关系:
原串 a b b a d d
新串 # a # b # b # a # d # d #
p[i] 1 2 1 2 5 2 1 2 1 2 3 2 1
可以看出这样化偶为奇,并且最长回文子串的长度就是max(p[i])-1,因为假设所求长度为len,中心为j,加上中间的特殊字符后长度变为2*len+1,而p[j]=[2*len+1]+1=len+1。
关键在于求p[i],分两种情况,一种是i在某一个回文子串s中,且以i为中心的回文串被完全包含在s中,则p[i]为关于s的对称点p[j],而由于p[]是从左向右依次得出的,所以p[j]一定已经得出;另一种是当i为中心的回文串长于s,则由于超出s的部分未知,我们无法确定p[i]的值,不能直接读取p[j]的值,而此时p[i]的值应至少为s的最右端-i。记已经扫描到的最右端为max,属于回文串的中心为id。如:
. . . . . . 1 2 3 4 5 6 7 8
# b # a # b # c # b # a # d
j id i
p[j]=4 p[s]=6 p[i]=1
若以i为中心的回文串不在某个回文串中,则将p[i]定为1,此时,以i为中心,向左右扩展p[i],直至求出p[i]的值。如果扫描到的超过了max,则更新max及对应的id,这样就可以保证只扫一遍得出结果。
这篇文章讲得更为详细 http://acm.uestc.edu.cn/bbs/read.php?tid=3258
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 var 2 a:array[0..250000]of char; 3 p:array[1..250000]of longint; 4 i,len:longint; 5 function min(p,q:longint):longint; 6 begin 7 if p>q then exit(q) else exit(p); 8 end; 9 procedure scanin; 10 var 11 c:char; 12 begin 13 read(c); 14 len:=0; 15 a[0]:='$'; 16 while (ord(c)>=ord('a'))and(ord(c)<=ord('z')) do begin 17 inc(len); 18 a[len]:='#'; 19 inc(len); 20 a[len]:=c; 21 read(c); 22 end; 23 inc(len); 24 a[len]:='#'; 25 end; 26 procedure manacher; 27 var 28 id,max:longint; 29 begin 30 max:=1; 31 id:=1; 32 for i:=1 to len-1 do begin 33 if (max>i) then 34 p[i]:=min(p[2*id-i],max-i) 35 else 36 p[i]:=1; 37 while (a[i+p[i]]=a[i-p[i]]) do inc(p[i]); 38 if (p[i]+i>max) then begin 39 max:=p[i]+i; 40 id:=i; 41 end; 42 end; 43 end; 44 procedure print; 45 var 46 max:longint; 47 begin 48 max:=-123456789; 49 for i:=1 to len do 50 if p[i]>max then max:=p[i]; 51 writeln(max-1); 52 end; 53 begin 54 scanin; 55 manacher; 56 print; 57 58 end.