manacher-模板-hd-3068

 1 /*
 2   题意:给一个字符串,求该串的最长回文串的长度;
 3   算法:Manacher
 4   O(n)复杂度,求以每一个字符为中心的最长汇文串的长度;
 5   这个算法把奇数和偶数的情况和在一起来考虑了;
 6  */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstring>
10 #include<algorithm>
11 using namespace std;
12 int n;
13 int p[300005];
14 char s[110005],str[300005];
15 /*
16    首先第一步是将原来的串扩展。避免奇偶分类讨论,在开头设置一个不用的东西,从1开始用#分隔;
17    字符串的长度相应的改变;
18    最后要记得在新串的最后加;
19    */
20 void init()
21 {
22     str[0]='@';
23     str[1]='#';
24     for(int i=0;i<n;i++)
25     {
26         str[i*2+2]=s[i];
27         str[i*2+3]='#';
28     }
29     n=2*n+2;
30     str[n]=0;
31 }
32 /*
33    计算以每一个字符作为中心的最长回文串的长度,但是在后面可以进行剪枝,避免多余的比较,就是利用已有的回文串,在前面的某个字符作为中心的情况计算过了的话就可以直接用它的数据,因为他们在对称的位置上,在一定的范围内周边的字符是一样的,id就是用来记录上一个回文串的中心是哪一个,用来计算对称位置用的,最后扫一遍p数组,结果减一;
34  */
35 void pk()
36 {
37     int mx=0,id=0;
38     for(int i=1;i<n;i++)
39     {
40         if(mx>i)
41         {
42             p[i]=min(p[2*id-i],p[id]+id-i);
43             //p[id*2-i]表示i的对称位置上的那个字符的回文串长度,p[id]+id-i表示的是以id为中心的回文串的边界距离i的距离,在这个距离以内的都可用对称点的数据,超出的就得自行比较了;省下一部分的比较;
44         }
45         else
46             p[i]=1;
47         for(;str[i+p[i]]==str[i-p[i]];p[i]++);
48         if(mx<p[i]+i)
49         {
50             //mx记录回文串的最远的边界;
51             mx=p[i]+i;
52             id=i;
53         }
54     }
55 }
56 int main()
57 {
58     while(scanf("%s",s)!=EOF)
59     {
60         memset(p,0,sizeof(p));
61         n=strlen(s);
62         init();
63         pk();
64         int ans=0;
65         for(int i=1;i<n;i++)
66         {
67             if(p[i]>ans)
68                 ans=p[i];
69         }
70         printf("%d
",ans-1);
71     }
72 
73     return 0;
74 }
View Code
原文地址:https://www.cnblogs.com/by-1075324834/p/4514641.html