Manacher:最长回文

来源:互联网 发布:淘宝上的糖画机好用吗 编辑:程序博客网 时间:2024/05/19 19:41
最长回文Time Limit:2000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u
SubmitStatusPracticeHDU 3068

Description

给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
 

Input

输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
 

Output

每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
 

Sample Input

aaaaabab
 

Sample Output

43
#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 110005char str[N];char strf[2 * N];int rad[2 * N];int len;void init(){    int i, j;    len = strlen(str);    strf[0] = '@';    strf[1] = '#';    for(i = 0; i < len; i ++){        strf[i * 2 + 2] = str[i];        strf[i * 2 + 3] = '#';    }    strf[len * 2 + 2] = '$';    len = len * 2 + 3;}int main(){    while(~scanf("%s", str)){        init();        //cout << strf << endl;        memset(rad, 0, sizeof(rad));        int mx = 0, id;        int len = strlen(strf);        for(int i = 1; i < len - 1; i++){            if(mx > i)                rad[i] = min(rad[2 * id - i], rad[id] + id - i);            else                rad[i] = 1;            while(strf[i + rad[i]] == strf[i - rad[i]])                rad[i]++;            if(rad[i] + i > mx){                mx = rad[i] + i;                id = i;            }        }        int ans = 0;        for(int i = 0; i < len; i ++){            //printf("%d\n", rad[i]);            if(rad[i] > ans)                ans = rad[i];        }        printf("%d\n", ans - 1);    }    return 0;}

manacher部分还可以写成如下形式,个人认为更容易理解(参考点击打开链接),不过注意到最后ans不用再减一

        for(int i = 1, j = 0, k; i < len;){            while(strf[i - j - 1] == strf[i + j + 1])                j ++;            rad[i] = j;            for(k = 1; k <= j && rad[i - k] != rad[i] - k; k ++){                rad[i + k] = min(rad[i - k], rad[i] - k);            }            i += k;            j = max(j - k, 0);        }