Manacher - Girls’ research - HDU - 3294
题意:
多 组 测 试 用 例 , 每 组 包 括 一 个 字 符 c h 和 一 个 字 符 串 s 。 字 符 串 c h 表 示 : 将 s 中 的 c h 替 换 为 a , 其 它 字 符 响 应 的 做 同 等 “ 长 度 ” 的 替 换 。 举 个 栗 子 : 若 c h = b , 那 么 s 中 的 b 替 换 为 a , 则 a 替 换 为 z , c 替 换 为 b , d 替 换 为 c , . . . 。 对 替 换 过 后 的 字 符 串 s , 求 第 一 个 出 现 的 最 大 回 文 子 串 的 开 始 和 结 束 位 置 , 同 时 输 出 这 个 回 文 子 串 。 若 回 文 子 串 长 度 小 于 2 , 输 出 N o s o l u t i o n ! 。 多组测试用例,每组包括一个字符ch和一个字符串s。\\字符串ch表示:将s中的ch替换为a,其它字符响应的做同等“长度”的替换。\\举个栗子:若ch=b,那么s中的b替换为a,则a替换为z,c替换为b,d替换为c,...。\\\ \\对替换过后的字符串s,求第一个出现的最大回文子串的开始和结束位置,同时输出这个回文子串。\\若回文子串长度小于2,输出No\ solution!。 多组测试用例,每组包括一个字符ch和一个字符串s。字符串ch表示:将s中的ch替换为a,其它字符响应的做同等“长度”的替换。举个栗子:若ch=b,那么s中的b替换为a,则a替换为z,c替换为b,d替换为c,...。 对替换过后的字符串s,求第一个出现的最大回文子串的开始和结束位置,同时输出这个回文子串。若回文子串长度小于2,输出No solution!。
Sample Input
b babad
a abcd
Sample Output
0 2
aza
No solution!
如 样 例 1 : b − > a , a − > z , d − > c , 得 到 新 串 a z a z c , 第 一 个 出 现 的 最 大 回 文 子 串 是 a z a 。 如样例1:b->a,a->z,d->c,得到新串azazc,第一个出现的最大回文子串是aza。 如样例1:b−>a,a−>z,d−>c,得到新串azazc,第一个出现的最大回文子串是aza。
数据范围:
字
符
串
长
度
n
<
=
200000
。
T
i
m
e
l
i
m
i
t
:
1000
m
s
,
M
e
m
o
r
y
l
i
m
i
t
:
32768
k
B
字符串长度n<=200000。\\Time \ limit:1000 ms,Memory \ limit:32768 kB
字符串长度n<=200000。Time limit:1000ms,Memory limit:32768kB
题解:
先 转 化 字 符 串 , 再 用 马 拉 车 。 转 化 : 看 c h 与 a 之 间 的 间 隔 , 其 他 字 符 都 减 去 这 个 间 隔 , 若 减 去 后 的 A S C I I 码 小 于 a , 就 加 26 。 马 拉 车 第 一 个 最 大 回 文 串 的 所 在 的 中 心 位 置 i ( 下 标 从 1 开 始 ) , 实 际 中 心 位 置 为 p o s = ⌊ i 2 ⌋ 。 最 大 长 度 为 a n s , 则 回 文 半 径 为 ⌊ ( a n s + 1 ) 2 ⌋ , 则 起 始 位 置 为 p o s − ⌊ ( a n s + 1 ) 2 ⌋ , 结 束 位 置 : p o s − ⌊ ( a n s + 1 ) 2 ⌋ + a n s − 1 。 先转化字符串,再用马拉车。\\转化:看ch与a之间的间隔,其他字符都减去这个间隔,若减去后的ASCII码小于a,就加26。\\\ \\马拉车第一个最大回文串的所在的中心位置i(下标从1开始),实际中心位置为pos=\lfloor\frac{i}{2}\rfloor。\\最大长度为ans,则回文半径为\lfloor\frac{(ans+1)}{2}\rfloor,则起始位置为pos-\lfloor\frac{(ans+1)}{2}\rfloor,结束位置:pos-\lfloor\frac{(ans+1)}{2}\rfloor+ans-1。 先转化字符串,再用马拉车。转化:看ch与a之间的间隔,其他字符都减去这个间隔,若减去后的ASCII码小于a,就加26。 马拉车第一个最大回文串的所在的中心位置i(下标从1开始),实际中心位置为pos=⌊2i⌋。最大长度为ans,则回文半径为⌊2(ans+1)⌋,则起始位置为pos−⌊2(ans+1)⌋,结束位置:pos−⌊2(ans+1)⌋+ans−1。
注意:
s t r l e n 函 数 不 要 写 在 循 环 里 面 , 常 数 太 大 。 strlen函数不要写在循环里面,常数太大。 strlen函数不要写在循环里面,常数太大。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=200010;
char s[N],ch[2];
char Ma[N*2]; //最大回文串+特殊符号
int Mp[N*2]; //Mp[i]:以i为中心的最大回文半径+1
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=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%s",ch,s))
{
int d=*ch-'a';
int len=strlen(s);
for(int i=0;i<len;i++)
{
if( s[i]-d < 'a') s[i]=char(s[i]-d+26);
else s[i]=char(s[i]-d);
}
Manacher(s,len);
int ans=0,pos=0;
for(int i=0;i<2*len+2;i++)
{
if(ans<Mp[i]-1)
{
ans=Mp[i]-1;
pos=i/2;
}
}
if(ans>=2)
{
printf("%d %d\n",pos-(ans+1)/2,pos-(ans+1)/2+ans-1);
for(int i=pos-(ans+1)/2;i<=pos-(ans+1)/2+ans-1;i++) printf("%c",s[i]);
puts("");
}
else puts("No solution!");
}
return 0;
}