/ *
Manacher最長の文字列回文サブストリングアルゴリズム、O(n)の
文字列aaabbaについては、最長の部分文字列は、パリンドロームアバある
ほとんどを得ているあなたは(n)をOにしたい場合は、対称軸を持っている必要があります回文構造部分文字列のために長いパリンドロームストリングは、我々は、対称の各軸を列挙する必要があり、O(1)再帰的であることができる
このような無駄な「#」文字は、我々は無視することができるようになるように一回の操作でmanacherが中間位置に挿入されるように2つの文字の対称の中間軸
対称軸上の唯一の土地を考慮した場合(上位AB&間の対称軸は、対称軸に基づいて文字ならば、より良い探しています)
* /
manacher
暴力
決定された各サブストリングはパリンドローム配列を横断するかどうか、すべてのサブストリングを識別し、Oの時間複雑度(\(N ^ 3} {\) )
最適化
列挙された各位置は、最大回文文字列の位置を見つけるために拡張することができるように、パリンドローム配列は、対称である
時間計算量Oを(\(^ {N-2} \) )
manacher
分析のために最適化されたアルゴリズム見つけ
奇数長さのためにとパリンドロームパリンドローム対称軸の偶数の長さが同じではありませんが、文字が奇数、偶数は2つの文字の間、分類議論する必要があるされ
、いくつかの意志の部分文字列をこれは、いくつかの回訪問されました
文字列の長さの問題に対処
元の文字列では、同じ無関係の挿入ワード長は2 * LEN + 1は、奇数になっているとなり
一にバインドされた配列を防止するための更なる文字を追加する必要がありますか???
回文配列見上げる
定義された半径回文、対称軸からの距離に左端または右端の位置にある文字列が半径パリンドロームと呼ばれる回文を
チャー:## Bが#、C#のB ##の
P [I]:1 2 1 2 1 6 1 2 1 2 1
P [I] - 1 0 1 0 1 0 5 0 1 0 1 0
iは1 2 3 4 5 6 7 8 9 10 11
だから、答えは最大のp [i]には-1です
ので、質問は、pの配列を見つける方法であります
[I]は、直接1が割り当てられていない文字列、P拡張パリンドローム配列パリンドローム対称性を使用して、しかし以前決定P [J]によれば、0 <J <私は
MXが生成されたすべての文字を最大バック表すWEテキストストリングの最大右境界は、
IDは、最大右境界の対称軸線の発生位置を示しています。
ケース1:私は<MXの
ケース2:I> = MX
テンプレート
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=11e6+5;
char str[maxn];
int Mp[maxn<<1];
char Ma[maxn<<1];//存放包含无用字符#的字符串
int len;
void Manacher(char str[],int len){
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++){
Ma[l++]=str[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++){
Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
if(i+Mp[i]>mx){
mx=i+Mp[i];
id=i;
}
}
}
int main(){
while(~scanf("%s",str)){
len=strlen(str);
Manacher(str,len);
int ans=0;
for(int i=0;i<2*len+2;i++){
ans=max(ans,Mp[i]-1);
}
printf("%d\n",ans);
}
return 0;
}