最长回文

来源:互联网 发布:网络综艺为什么这么火 编辑:程序博客网 时间:2024/06/08 17:52

**bzoj 2565: 最长双回文串 manacher算法
2565: 最长双回文串
Time Limit: 20 Sec Memory Limit: 256 MB**

题目连接
http://www.lydsy.com/JudgeOnline/problem.php?id=2565

Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。

Input
一行由小写英文字母组成的字符串S。

Output

一行一个整数,表示最长双回文子串的长度。

Sample Input
baacaabbacabb

Sample Output
12

先简单的说一下 题目的意思,给你一个 字符串,让你求出 最长的 双回文字串,双回文字串就是, 该字符串可以 有 两个 回文字符串 组成, 这两个 回文字符串的长度 不小于 1 。题目的意思很简单,下面说一下我写的程序的 解体思路,我 先是 运用 manacher 函数的出 p[] 数组,p[i] 表示 以 str[i] 为中心的 的 最大的回文字符串的长度,然后 ,定义了, 一个 L【】 数组, L[i] 表示 包含 str[i] 这个字符的 中心点 最 靠左边 的 回文子字符串的 中心 字符 的 下标, 然后 有定义了一个 R[] 数组, 与 上面的 L[] 数组功能类似, L[i] 存储 包含 str[i] 这个字符的 中心点 最 靠右边 的 子 回文字符串 的 中心 字符 的 下标。

然后 根据 循环 运用 p【】数组 对 R L 两个 数组分别进行赋值。
赋值 之后, 通过 一个 循环 遍历, 得出 最唱 双 回文字符串的 长度。
循环 遍历的 核心 代码 为:

 for(int i = 1; i < len; i++)        ans = max(ans, R[2*i+1] - L[2*i+1]);

代码的意思 就是 对于 一个 字符 str[2*i+1] 包含该字符 的 最右边的 回文串的 中心 字符的 下标 减去 包含 个字符的 最左边 的 回文串 的 中心 字符 的 下标;大家 把这个 解释 与 题目种 所说的 双 回文字符串的 定义 结合 在一起 想一想 就会明白的;

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#define MAX 100010using namespace std;char str[MAX*2];int p[MAX*2];int R[MAX*2];int L[MAX*2];void Manacher(){    int len = strlen(str);    for(int i = len; i >= 0; i--)    {        str[2*i+2] = str[i];        str[2*i+1] = '#';    }    str[0] = '?';    int id = 0;    int maxlen = 0;    for(int i = 2; i <= 2*len; i++)    {        if(id+p[id] > i)            p[i] = min(p[id-(i-id)], p[id]-(i-id));        else            p[i] = 1;        while(str[i+p[i]] == str[i-p[i]])            p[i]++;        if(i+p[i] > id+p[id])            id = i;        maxlen = max(maxlen, p[i]);    }    //  求 R[] 与  L[]  数组    int pos = 1;    for(int i = 2; i <= 2*len; i++)        for( ; pos <= i+p[i]-1; pos++)            L[pos] = i;    pos = 2*len;    for(int i = 2*len; i >= 2; i--)        for( ; pos >= i-p[i]+1; pos--)            R[pos] = i;    int ans = 0;    for(int i = 1; i < len; i++)// 这里2*i+1 表示 ‘#’的下表 而且  是 包含在 用用字符 之间的 添加字符 的下标         ans = max(ans, R[2*i+1] - L[2*i+1]);    printf("%d\n", ans);}int main(){    scanf("%s", str);    memset(L, 0, sizeof(L));    memset(R, 0, sizeof(R));    Manacher();    return 0;}