HDU 3068 最长回文(马拉车模板题)
马拉车可以求出每个字符为中心的最长回文串
# 1 # 2 # 2 # 1 # 2 # 2 #
1 2 1 2 5 2 1 6 1 2 3 2 1
'#'字符对应的p[i]对应的回文串在原串s里都是偶数长度的,而'1','2'对应的p[i]对应的回文串在原串s里都是奇数长度的
总结O(n)求最长回文子串,关键是p[i]数组,p[i]表示的是处理过的字符串t里以i位置字符为中心的最长回文子串半径然后,p[i]-1得到的就是以i位置字符为中心的最长回文子串长度(在s串里),然后如果要确定一个回文子串的位置的话,起始位置是中间位置减去半径再除以2,即(i-p[i])/2,这个是该回文子串在s串里的起始位置,s和t都是从0下标开始放的。
#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define PI acos(-1)
#define eps 1e-8
#define ll long long
#define fuck(x) cout<<#x<<" "<<x<<endl;
typedef pair<int,int> pii;
const int maxn=1e6+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
//int lowbit(int x){return x&-x;}
//void add(int x,int v){while(x<=n)bit[x]+=v,x+=lowbit(x);}
//int sum(int x){int ans=0;while(x>=1) ans+=bit[x],x-=lowbit(x);return ans;}
char t[maxn];
string Manacher(string s) {
// Insert '#'
string t = "$#";
for (int i = 0; i < s.size(); ++i) {
t += s[i];
t += "#";
}
// Process t
vector<int> p(t.size(), 0);
int mx = 0, id = 0, resLen = 0, resCenter = 0;
for (int i = 1; i < t.size(); ++i) {
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
if (mx < i + p[i]) {
mx = i + p[i];
id = i;
}
if (resLen < p[i]) {
resLen = p[i];
resCenter = i;
}
}
return s.substr((resCenter - resLen) / 2, resLen - 1);
}
int main(){
while(scanf("%s",t)!=EOF)
{
cout<<Manacher(t).size()<<endl;
}
return 0;
}