hdu3068 manacher算法 最长回文子…

来源:互联网 发布:js如何设置translatey 编辑:程序博客网 时间:2024/05/16 14:09

解题报告

题目 http://acm.hdu.edu.cn/showproblem.php?pid=3068
题目大意:求给定串的最长回文子串(2009多校题目)

算法 manacher;

思路 :枚举每个点向左向右扩展,看最远能扩展到哪儿.但是普通的枚举是n^2的,肯定超时。现在我们想kmp或扩展kmp一样,给字符串定义一个nex数组,nex[i]表示以i为中心最远能向右扩展的长度,使得s[i – nex[i] + 1……. i + nex[i]-1]形成的回文。然后我们利用这个数组,在O(n)的时间内求出每个inex[i]。在其他算法中,奇数回文和偶数回文经常给我们带来麻烦,这个算法中,我们第一步要进行的是将每个字符后边(包括开头)加入一个字符(不在串儿的字符集中就行),一般用’#”. 这样就都转换为了奇数的情况。

例如      abba (偶)

        改为  #a#b#b#a# (最长为以第3#为中心)

            aba    (奇) 

改为   #a#b#a# (最长为以b为中心)      

剩下的就是在我们知道了nex[0]…….nex[i – 1]如何求nex[i]p记录前i-1个字符中以某个字符id为中心最远能向右扩展到的位置。 

代码:

void Get_nex(){

   int i, p, id;

   p = 0;

   fup(i, 1, L2){

      if(p > i) nex[i]= MIN(nex[2 * id -i], p -i);

      else nex[i] = 1;

      for(; tem[i+ nex[i]] == tem[i - nex[i]];nex[i]++);

      if(p <i + nex[i]) p = i + nex[i],id =i;

   }

}

 

 

if(p > i) nex[i]= MIN(nex[2 * id -i], p -i);

这是代码中最核心的一句话,它的作用是让我们在以i为中心向左右扩展时,尽量减少重复的比较,当p > i 时会有两种情况。设j = 2 *id –i id为中心i的对称位置。

第一:当以i为中心的回文和以j为中心的回文都在以id为中心的回文中时。

 由于回文的对称性,这时nex[i]最小为nex[j] 这是表达式前半部分。

第二:当以i为中心的回文或以j为中心的回文不在以id为中心的回文中时。

       qa b a c a b a c          

hdu3068 <wbr>manacher算法 <wbr>最长回文子串hdu3068 <wbr>manacher算法 <wbr>最长回文子串hdu3068 <wbr>manacher算法 <wbr>最长回文子串          id   i

或:

c a b a c a b q c          

hdu3068 <wbr>manacher算法 <wbr>最长回文子串hdu3068 <wbr>manacher算法 <wbr>最长回文子串 hdu3068 <wbr>manacher算法 <wbr>最长回文子串           id   i

这时以i为中心的最长回文不一定大于nex[i],但是由于回文的对称性,他最小是p-i(nex[j]大时)nex[j]

收获以经验 :又学到了一种新算法,happy

提交情况 accepted1

ACcode

 

#include <cstdio>

#include <cstring>

#include <cctype>

#include <cmath>

#include <cstdlib>

#include <ctime>

#include <map>

#include <set>

#include <vector>

#include <algorithm>

using namespace std;

 

typedef int I64;

typedef double real;

 

#define MAX(a, b) ((a) > (b) ?(a) :(b))

#define MIN(a, b) ((a) < (b) ?(a) :(b))

#define mem(a, b) memset(a, b, sizeof(a))

#define fup(i, a, b) for(i = a; i < b;++i)

#define fdn(i, a, b) for(i = a; i > b;--i)

#define INF 210000000

 

I64 Gcd(I64 a, I64 b){return b ? Gcd(b, a% b) : a;}

I64 Lcm(I64 a, I64 b){return a / Gcd(a, b)* b; }

 

#define MAXL 110100

 

char s[MAXL], tem[MAXL * 2];

I64 L1, L2, nex[MAXL* 2];

 

void Get_tem(){

   int t = 0, i = 0, k = 1;

   tem[0] = '$';

   while(s[i]!= '\0'){

      tem[k ++] = t ?s[i ++] : '#';

      t ^= 1;

   }

   tem[k++] = '#';

   tem[L2 = k] = '\0';

}

 

void Get_nex(){

   int i, p, id;

   p = 0;

   fup(i, 1, L2){

      if(p >i) nex[i] = MIN(nex[2 * id -i],p - i);

      else nex[i] = 1;

      for(; tem[i+ nex[i]] == tem[i - nex[i]];nex[i]++);

      if(p <i + nex[i]) p = i + nex[i],id =i;

   }

}

 

 

int main(){

   I64 i;

   while(~scanf("%s",&s)){

      Get_tem();

      Get_nex();

      I64 min = 0;

      fup(i, 1, L2)

          if(min < nex[i] - 1) min = nex[i]-1;

      printf("%d\n",min);

   }

   return 0;

}

 

原创粉丝点击