Manacher演算法學習: http://blog.csdn.net/vsooda/article/details/8725580
代碼1:轉自http://blog.csdn.net/sprintfwater/article/details/8709458
#include <stdio.h>#include <string.h>#include <stdlib.h>#define MAXN 100005int a[MAXN * 2];struct Rem{int left;int right;}rem;int odd[2 * MAXN]; //儲存每個元素為中心的迴文對數int min(int a, int b){return (a < b) ? a : b;}int fun(int i, int m, int N) //嘗試對外繼續擴張{int l = i - m - 1, r = i + m + 1;int ret = 0;for(;(l > 0)&&(r <= N);--l, ++r){if((a[r] == -1) || ((a[l] == a[r]) && ((r - l == 2)||(a[r] <= a[r - 2]) )))++ret;else break;}return ret;}int main(){int T, N;for(scanf("%d", &T); T--; ){scanf("%d", &N);int i = 0;a[++i] = -1;while(N--){scanf("%d", &a[++i]);a[++i] = -1;}N = i;rem.left = rem.right = 0;int ans = 1;memset(odd, 0, sizeof(odd));for(int i = 1; i <= N; ++i){int m = 0;if(rem.right > i)m = min(rem.right - i, odd[rem.left + (rem.right - i)]);//利用對稱左右對稱性質最佳化odd[i] = m + fun(i, m, N);if(i + odd[i] > rem.right)//當有最大右邊覆蓋,記錄下來{rem.left = i - odd[i];rem.right = i + odd[i];}if(odd[i] > ans)ans = odd[i];}printf("%d\n", ans);}return 0;}
代碼2:轉自http://hi.baidu.com/chenwenwen0210/item/51b72039793833f56d15e9ba
#include<stdio.h>#include<math.h>#include<string.h>#include<map>#include<algorithm>#include<queue>using namespace std;typedef __int64 lld; const int MAX=110000*2;int str[MAX];//原字串int sb[MAX];int p[MAX];//表示以i為中心的迴文半徑,/*p[i]-1剛好是原字串以第i個為中心的迴文串長度。畫畫圖就知道了,因為兩端配匹的肯定是字元g*//*Mancher主演算法。功能:求出以i為中心的迴文半徑p[i];參數:傳入構造好的字串長度特殊說明:因為前面加了一個無效字元,所以下標從1開始。例題:http://acm.hdu.edu.cn/showproblem.php?pid=3068http://poj.org/problem?id=3974http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=3780http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=3769http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=12581#problem/Ahttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3661http://acm.hdu.edu.cn/showproblem.php?pid=3948*/bool dig(char x){return x>='0'&&x<='9';}int getval(){ int ret=0,sign=1; char c; while(!dig(c=getchar())&&c!='-'); if(c=='-')sign=-1; else ret=c-'0'; while(dig(c=getchar()))ret=ret*10+c-'0'; return ret*sign;}void Manacher(int n){ int i; int mx=0;//記錄前面迴文串最長影響到的地方。不一定是最長迴文串造成的。 int id;//最長影響串的ID; p[0]=0; for(i=1;i<n;i++) { p[i]=1;//至少是1 if(mx>i)//i受到影響即,id+p[id]-1>=i; { p[i]=p[2*id-i];//2*id-i是i關於id的對稱點相當於是id-(i-id); if(mx-i<p[i])p[i]=mx-i; //由於對稱點的迴文半徑可能超過mx-i,因為mx後面的還沒有配過 //所以要取小的。等等繼續配 } //向兩端配匹 while(str[i-p[i]]==str[i+p[i]]) { if(str[i+p[i]]==1) { p[i]++; } else { int a=i-p[i]; int b=i+p[i]; if(a+2<=b-2&&str[a]<=str[a+2]&&str[b-2]>=str[b]) { p[i]++; continue; } else if(a==b) { p[i]++; continue; } else if(a+2>b-2) { p[i]++; continue; } break; } } if(i+p[i]>mx) { mx=i+p[i]; id=i; } }} /*功能:構造字串,在每一個字元前插入一個,g,一般用'#'第一個字元前面再插入,first,一般用'$'最後再插入g字元總之不是在輸入中出現的字元就行了。比如abb,構造成$#a#b#b#參數:<first,第一個字元>,<g,一般字元> 傳回值:構造好的字串長度*/int pre(int first,int g,int m){ int i,n=0; memcpy(sb,str,sizeof(int)*(m+2)); str[0]=first; n++; for(i=0;i<m;i++) { str[n++]=g; str[n++]=sb[i]; } str[n++]=g; str[n]=3; return n;}int main(){ int n; int i; int CS=1; int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=0;i<n;i++) { //scanf("%d",&str[i]); str[i]=getval(); } n=pre(0,1,n); Manacher(n); int ans=0; for(i=1;i<n;i++) { if(p[i]>ans)ans=p[i]; } printf("%d\n",ans-1); } return 0;}