Manacher - Girls' research - HDU - 3294

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!。 chschschach=bsbaazcbdc... s2No 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。 1b>a,a>z,d>cazazcaza

数据范围:
字 符 串 长 度 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<=200000Time limit1000msMemory limit32768kB

题解:

先 转 化 字 符 串 , 再 用 马 拉 车 。 转 化 : 看 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。 chaASCIIa26 i(1)pos=2ians2(ans+1)pos2(ans+1)pos2(ans+1)+ans1

注意:

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值