题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3294
题目大意:输入一个字符ch和一个字符串,问如果把ch当作'a'的话,字符串的每个字符也要做相应变化,如b aa,若b为'a',则b前面的a就为'a'前面的'z',这里是循环表示,输出字符串的最长回文子串,如果最长回文子串串长为1,输出No solution!
几乎是模板题,唯一的特别之处就是要输出回文串字符,所以要记录max(Mp[i])对应的在原串中的字符区间,根据Manacher算法的步骤逆推即可,所以要对算法的基础步骤要熟练,毕竟是简单的算法。
关于逆推这步:对应Manacher执行到算出Mp[i]时,实际上找出的原串中的回文串的位置[L,R]=[ (i-Mp[i])/2 , (i+Mp[i]-4)/2 ] (字符串从0位置开始)
这步推导经常用到,当场推还有点小麻烦...而且只限于当前最大回文串的位置,拓展至有些位置不是这个表达式,但是这些位置为中心的肯定不是当前最大的回文串,所以不予考虑
//171MS 2536K
#include<cstdio>
#include<iostream>
#include<cstring>
#define M 200100
using namespace std;
int Mp[M<<1];
char s[M],Ma[M<<1];
int maxn,L,R;
void Manacher(char s[],int len)
{
int l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0;i<len;i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
int mx=0,id=0;
for(int i=1;i<l ;i++){
Mp[i]= mx>i? min(Mp[2*id-i],mx-i) :1;
while(Ma[Mp[i]+i ]==Ma[i-Mp[i] ]) Mp[i]++;
if(Mp[i]+i>mx){
mx=Mp[i]+i;
id=i;
}
if(Mp[i]-1>maxn){
maxn=Mp[i]-1;
L = (i-Mp[i])>>1; //根据对原串的处理逆推
R = (i+Mp[i]-4)>>1; //根据对原串的处理逆推
}
}
}
int main ()
{
char a[5];
while(~scanf("%s%s",a,s)){
maxn=-1;
int len=strlen(s);
Manacher(s,len);
if(maxn==1) printf("No solution!");
else {
printf("%d %d\n",L,R);
for(int i=L;i<=R;i++){
printf("%c",'a'+((s[i]-a[0])+26)%26); //小技巧,把值循环圈定在26个字母范围内
}
}
puts("");
}
return 0;
}