HDU3068--------8.7初识Manacher

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3068

求最长回文长度;

直接上代码

#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <math.h>
#include <map>
#define sd(qwe) scanf("%d",&qwe)
#define ss(asd) scanf("%s",asd)
#define sc(xcv) scanf("%c",&xcv)
#define xh(ert,rty,tyu) for(int ert=rty;ert<=tyu;ert++)
#define fxh(u,i,o) for(int u=i;u>=o;u--)

using namespace std;
const int maxn=100005;
char str[2*maxn];
int p[2*maxn];
int main()
{
    while(~ss(str)){
        int len=strlen(str),id=0,maxlen=0;
        fxh(i,len,0){
        str[2*i+2]=str[i];
        str[2*i+1]='#';
        }
        str[0]='*';
        xh(i,0,2*len){
        if(p[id]+id>i)p[i]=min(p[2*id-i],p[id]+id-i);
        else p[i]=1;
        while(str[i-p[i]]==str[i+p[i]])p[i]++;
        if(id+p[id]<i+p[i])id=i;
        if(maxlen<p[i])maxlen=p[i];

        }
        cout<<maxlen-1<<endl;
    }
    return 0;
}

首先该算法巧妙的将所有回文串变成了奇数串.变奇数串是在每个空隙都加一个没有出现过的字符,注意,还在前加了‘*’,之所以在后面没加是因为我在扩展时吧原字符串的‘\n’移到了最后.这个操作是防止越界。可以想象匹配第一个字符时如果str【0】和str【2】匹配就可能访问到str【-1】.!!!

p【i】代表以i为中心的最长回文串的长度-1!!!

id代表寻找到一个位置时在这前一段中找到的最长的.然后分两种情况,

如果当前查看的位置不在-p[id]到id到p[id]之间.那直接赋为1.(之后的while会对它两边进行扩展更新)

如果在之间.那就看相对于id 的对称位置的p值.取该值和p【id】的最小,不用担心,如果是对称位置的p值就对了,如果是p【id】就会在之后的while中继续扩展.每次都尝试更新id和maxlen。

猜你喜欢

转载自blog.csdn.net/qq_35557621/article/details/81487731