https://www.luogu.org/problemnew/show/P3805
回文串长度的奇偶性造成了对称轴的位置可能在某字符上,也可能在两个字符之间的空隙处
那么manacher对此的优化是在每两个字符中间插入另一个字符,如'#'。
用一个辅助数组r表示每个点能够扩展出的回文长度
我们先设置一个辅助变量maxright,表示已经触及到的最右边的字符
另外还要设置一个辅助变量mid,表示包含maxright的回文串的对称轴所在的位置
当i在maxright左边且在mid右边时:
设i关于mid的对称点为j,显然r[i]一定不会小于r[j]。(对称)
我们没必要保存j,j可以通过计算得出,为:(mid<<1)−i
那么我们就设置r[i]=r[j]然后继续尝试扩展,这样就可以较快地求出r[i],然后更新maxright和mid
当i在maxright右边时,我们无法得知关于r[i]的信息,只好从1开始遍历,然后更新maxright和mid
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 char t[11000010], a[11000010]; 6 int n, m, ans=0; 7 int r[23000000]; 8 int main() { 9 scanf("%s", t); 10 m=strlen(t); 11 a[0]=a[1]='#'; 12 for(int i=1; i<=m; i++){ 13 a[(i<<1)]=t[i-1]; 14 a[(i<<1)+1]='#'; 15 } 16 n=(m<<1)+2; 17 int mid=1, maxright=1; 18 r[1]=1; 19 for(int i=2; i<n; i++){ 20 if(i<maxright) r[i]=min(r[(mid<<1)-i], r[mid]+mid-i); 21 else r[i]=1; 22 while(a[i-r[i]]==a[i+r[i]]) r[i]++; 23 if(i+r[i]>maxright){ 24 maxright=i+r[i]; 25 mid=i; 26 } 27 if(r[i]>ans) ans=r[i]; 28 } 29 printf("%d ", ans-1); 30 return 0; 31 }