HDU - 3068 最长回文(马拉车Manacher)题解

思路:马拉车裸题,我们用一个p[i]数组代表以i为中心的最大回文半径。这里用了一个小技巧,如果一个串是aaaa这样的,那我们插入不相干的字符使它成为#a#a#a#a#,这样无论这个串是奇数还是偶数都会变成奇数,容易处理。马拉车的效率在于,在暴力处理前面的回文时,我们可以初始化后面的p[j],减少暴力的时间,这样复杂度就从O(n^2)变成了O(n)。这里要注意一下,我们得到的p[i]所指向的不一定是数字,也有可能是‘#’,比如$#a#b#b#a#中最大的是p[5]。

可以看看这个博客,很容易理解

代码:

#include<set>
#include<iostream>
#include<algorithm>
const int maxn = 110000+5;
const int INF = 0x3f3f3f3f;
using namespace std;
int p[maxn<<1];
char snew[maxn<<1],s[maxn];
int init(){
    int len = strlen(s),cnt = 0;
    snew[0] = '$';
    for(int i = 0;i < len;i++){
        snew[++cnt] = '#';
        snew[++cnt] = s[i];
    }
    snew[++cnt] = '#';
    snew[++cnt] = '\0';
    return cnt;
}
int Manacher(){
    int cnt = init();
    int id = 0,ans = -1;
    for(int i = 2;i < cnt;i++){
        if(p[id] + id > i){
            p[i] = min(p[2*id - i],p[id] + id - i);
        }
        else p[i] = 1;
        while(snew[i - p[i]] == snew[i + p[i]])
            p[i]++;
        if(id + p[id] < i + p[i])
            id = i;
        ans = max(ans,p[i] - 1);
    }
    return ans;
}
int main(){
    while(scanf("%s",s) != EOF){
        printf("%d\n",Manacher());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_14938523/article/details/81104200