题意:
给定一个字母,这个字母对应着真正的 a ,将字符串变为他所对应的字符串,求出这个字符串的最长回文串的起点和终点,并输出这个回文串
思路:
最长子串的长度是半径减1,起始位置是中间位置减去半径再除以2。
Manacher算法+公式,新串中的位置 i ,对应原始串的( (i-len[i])/2 , (i+len[i])/2-2 )
id为能延伸到最右端的位置的那个回文子串的中心点位置,mx是回文串能延伸到的最右端的位置
一开始将 id 的位置当成最长回文串位置 , 输入也没处理好。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int maxn=300010;
int len[2*maxn];
char s[maxn],str[2*maxn];
int id,mx,slen,cnt;
void init(char a)
{
int x = a-'a';
for(int i=0;i<slen;i++)
{
s[i] -= x;
if(s[i] < 'a')
s[i] += 26;
}
}
int Manacher()
{
memset(str,0,sizeof(str));
memset(len,0,sizeof(len));
int k = 0;
str[k++] = '$';
for(int i=0;i<slen;i++)
{
str[k++] = '#';
str[k++] = s[i];
}
str[k++] = '#';
mx = id = 0;
int sum = 0;
for(int i=1;i<k;i++)
{
if(i<mx)
len[i] = min(mx-i,len[2*id-i]);
else
len[i] = 1;
while(str[i-len[i]]==str[i+len[i]])
len[i]++;
if(len[i]+i > mx)
{
mx = len[i]+i;
id = i;
if(len[i]>sum)
{
cnt = i;
sum = len[i];
}
}
}
return sum-1;
}
int main()
{
char a[2];
int ans;
while(~scanf("%s%s",a,s))
{
slen = strlen(s);
init(a[0]);
ans = Manacher();
if(ans<2)
printf("No solution!\n");
else
{
int l = (cnt-len[cnt])/2;
int r = (cnt+len[cnt])/2-2;
printf("%d %d\n",l,r);
for(int i=l;i<=r;i++)
printf("%c",s[i]);
printf("\n");
}
}
return 0;
}