最长回文

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

代码如下:

 

View Code
 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.
posted @ 2012-07-11 17:30  wangziyun  阅读(298)  评论(1编辑  收藏  举报
神奇的东西