hdu 3068 最长回文
这是一道最长回文串Manacher的裸题;
还是先讲讲里面使用dp的思想对Manacher的理解吧!
Manacher算法就是处理出前面以id为中点,半径为Mp[id]的回文串的右边界mx;之后每次处理i时,就可以看i是否在mx内,若是在mx里面,就可以将Mp[i]的初始值设置为i关于id对称的2*id-i处的点j,这时就可以从这个基础上向左右延伸了,否则朴素的算法就是每次Mp[i]都从0开始;很容易知道当i不在前面的回文串中,就不能利用前面得到的结果, 只能从1开始;还有就是注下Ma[]的处理就行;
374MS 2652K 1041 B
#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
const int MAXN = 110011;
char Ma[MAXN<<1];
int Mp[MAXN<<1];
char ret[MAXN],s[MAXN];
void Manacher(const char s[],int len)
{
int l = 0;
Ma[l++] = '$';Ma[l++] = '#';
rep(i,len){
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = '\0';
int mx = 0,id;
rep(i,l-1){
Mp[i] = mx > i?min(mx-i,Mp[2*id-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()
{
int len,i,j;
while(scanf("%s",s+1) != EOF){
len = strlen(s+1);
Manacher(s,len);
int ans = 0,id;
for(i = 1;i < len*2;i++){
if(ans < Mp[i])
ans = Mp[i],id = i; //这里没有将 ans = Mp[i] - 1;而是在输出的时候
}
printf("%d\n",--ans);
/*id = id/2 - ans/2; // 处理输出最长回文字符串;
if(ans%2 == 0) id++;
for(i = 0;i < ans;i++)
putchar(s[id++]);*/
}
return 0;
}