题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371
这道题用到了Manacher算法,首先简单介绍一下Manacher算法:
----------------------------------------------------------------------------------------------
【转】http://blog.csdn.net/yzl_rex/article/details/7908259
一个专门针对回文子串的算法,其时间复杂度为O(n)
求回文串时需要判断其奇偶性,也就是求aba 和abba 的算法略有差距。然而,这个算法做了一个简单的处理,
很巧妙地把奇数长度回文串与偶数长度回文串统一考虑,也就是在每个相邻的字符之间插入一个分隔符,
串的首尾也要加,当然这个分隔符不能再原串中出现,一般可以用‘#’或者‘$’等字符。
这样一来,原来的奇数长度回文串还是奇数长度,偶数长度的也变成以‘#’为中心奇数回文串了。
接下来就是算法的中心思想,用一个辅助数组P 记录以每个字符为中心的最长回文半径,
也就是P[i]记录以Str[i]字符为中心的最长回文串半径。P[i]最小为1,此时回文串为Str[i]本身。
核心代码:
1 if (maxid > i){ 2 p[i] = min(p[2*id - i], maxid - i); 3 }
-----------------------------------------------------------------------------------------------
再回到本题,因为所给的数列为非负整数,所以用-1作为间隔,利用Manacher算法求出各点的最长回文,
然后因为 abbaab 可以理解为 abba 和 baab 两个回文串,所以在第一个回文串的末尾往回找,
如果回文串的长度大于两点之间的距离,且大于sum,则更新sum。
在遍历过程中进行简化,易知回文串必然是偶数个的,所以只遍历-1的点就可以了。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int MAXN = 200050; 6 int str[MAXN]; 7 int p[MAXN]; 8 int N; 9 int main(){ 10 int T; 11 int TT = 0; 12 int mx, pi; 13 int _max; 14 int j; 15 scanf("%d",&T); 16 while(T--){ 17 memset(p,0,sizeof(p)); 18 memset(str,0,sizeof(str)); 19 str[0] = -100; 20 str[1] = -1; 21 scanf("%d",&N); 22 getchar(); 23 N = N * 2 + 1; 24 for(int i = 2; i < N; i++){ 25 if( i % 2 == 0) 26 scanf("%d",&str[i]); 27 else str[i] = -1; 28 } 29 str[N++] = -1; 30 int lgt = N; 31 mx = 0; pi = 1; 32 for( int i = 1; i < lgt; i = i + 1){ 33 if(str[i] == -1){ 34 if( i < mx) 35 p[i] = min(p[2*pi-i],mx-i); 36 else 37 p[i] = 1; 38 while( str[i-p[i]] == str[i+p[i]]) 39 p[i]++; 40 if( p[i]+i > mx ){ 41 pi = i; 42 mx = p[i]+i; 43 } 44 } 45 } 46 _max = 0; 47 for(int i = 1; i < lgt; i = i + 1){ 48 if( p[i] > _max && str[i] == -1){ 49 while( j > lgt) j -= 2; 50 for( j = i + p[i] - 1; j - i + 1 > _max; j -= 2 ){ 51 if( p[j] >= j - i + 1) 52 _max = j - i + 1; 53 } 54 } 55 } 56 printf("Case #%d: %d\n",++TT,(_max-1)/2*3); 57 } 58 }
hdoj 5371 Hotaru's problem