【HDU3294,URAL1294】manacher算法

manacher算法用于计算最长回文子串。
上模板

    //s是原子符串,而w是在s的前面、后面、字符之间插入一个未出现的字符‘#’
    scanf("%s",s);
    w[0]='*';//防止越界,在最前面加上一个‘*’
    w[++len]='#';
    for(int tmp=strlen(s), i=0;i<tmp;++i)
    {
        w[++len]=s[i];
        w[++len]='#';
    }
    --len;

    //p[i]表示以i为中心向左右扩展的最长回文子串的长度
    p[1]=ans=maxd=1;
    for(int i=2;i<len;++i)
    {
        if(p[maxd]+maxd>i)p[i]=min(p[maxd+maxd-i],maxd+p[maxd]-i);
        else p[i]=1;
        while(w[i+p[i]]==w[i-p[i]])++p[i];
        if(ans<p[i])ans=p[i];
        if(maxd+p[maxd]<p[i]+i)maxd=i;
    }
    printf("%d\n",ans-1);

而HDU3294,URAL1297为manacher的裸题。

URAL1297:
题意:求一个字符串的最长回文子串

#include <cstdio>
#include <cstring>
#define MAXN 100005
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

char s[MAXN], a, w[MAXN];
int len, p[MAXN], maxd, ans;

int main()
{
    //freopen("data.txt","r",stdin);
    scanf("%s",w);
    s[0]='*', s[++len]='#';
    for(int tmp=strlen(w), i=0;i<=tmp;++i)
    {
        s[++len]=w[i];
        s[++len]='#';
    }
    --len;
    p[1]=ans=1, maxd=1;
    for(int i=2;i<len;++i)
    {
        if(p[maxd]+maxd>i)p[i]=min(p[maxd+maxd-i],p[maxd]-i+maxd);
        else p[i]=1;
        while(s[i+p[i]]==s[i-p[i]])++p[i];
        if(p[maxd]+maxd<p[i]+i)maxd=i;
        if(p[ans]<p[i])ans=i;
    }
    for(int i=ans-p[ans]+1, tmp=p[ans]-1;i<len&&tmp;++i)
    {
        if(s[i]=='#')continue;
        printf("%c",s[i]);
        --tmp;
    }
    return 0;
}

HDU3294:
题目链接
题意:将某一字符串先向左平移若干个单位(第一个字符-‘a’)。求最先出现的最长回文子串的起始位置、结束位置,并输出。

一开始以为第一个字符只会是’a’或’b’,然后就wa了几遍…

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 400050
using namespace std;

char ask[5], s[MAXN], w[MAXN];
int len, p[MAXN], ans, maxd;

int main()
{
    while(~scanf("%s",ask))
    {
        len=0;
        scanf("%s",s);
        w[0]='*';
        w[++len]='#';
        for(int tmp=strlen(s), i=0;i<=tmp;++i)
        {
            w[++len]=s[i];
            w[++len]='#';
        }
        len-=2;

        p[1]=ans=1, maxd=1;
        for(int i=2;i<len;++i)
        {
            if(p[maxd]+maxd>i)p[i]=min(p[maxd+maxd-i],p[maxd]+maxd-i);
            else p[i]=1;
            while(w[i+p[i]]==w[i-p[i]])++p[i];
            if(p[i]+i>p[maxd]+maxd)maxd=i;
            if(p[ans]<p[i])ans=i;
        }
        if(p[ans]<3)puts("No solution!");
        else
        {
            int Begin=(ans-p[ans]+2)/2-1, End=(ans+p[ans]-2)/2-1, k=ask[0]-'a';
            printf("%d %d\n",Begin,End);
            for(;Begin<=End;++Begin)
                printf("%c",(s[Begin]-'a'-k+26)%26+'a');
            puts("");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值