【题目链接】
http://poj.org/problem?id=3974
【算法】
解法1 :
字符串哈希
我们可以分别考虑奇回文子串和偶回文子串,从前往后扫描字符串,然后二分答案,检验可以用哈希
时间复杂度 : O(TNlog(N))
解法2
Manacher算法
这个算法可以在O(n)时间内求出最长回文子串,读者可以自行查阅资料,笔者不进行详细的介绍
两种方法的效率比对
显然,Manacher算法的复杂度是优于字符串哈希的,笔者的两份代码在POJ上的运行时间分别为4891MS和266MS
【代码】
代码1
/* Algorithm : Hash Time Complexity : O(Tnlog(n)) */ #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <exception> #include <fstream> #include <functional> #include <limits> #include <list> #include <map> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stdexcept> #include <streambuf> #include <string> #include <utility> #include <vector> #include <cwchar> #include <cwctype> #include <stack> #include <limits.h> using namespace std; #define MAXL 1000010 typedef unsigned long long ULL; const int P = 13331; int i,len,l,r,mid,tmp,ans,TC; ULL f[MAXL],ha[MAXL],hb[MAXL]; char s[MAXL]; inline ULL getha(int l,int r) { return ha[r] - ha[l-1] * f[r-l+1]; } inline ULL gethb(int l,int r) { int tmp = l; l = len - r + 1; r = len - tmp + 1; return hb[r] - hb[l-1] * f[r-l+1]; } int main() { f[0] = 1; for (i = 1; i < MAXL; i++) f[i] = f[i-1] * P; while (scanf("%s",s+1)) { len = strlen(s+1); if (s[1] == 'E') break; for (i = 1; i <= len; i++) ha[i] = ha[i-1] * P + (s[i] - 'a' + 1); reverse(s+1,s+len+1); for (i = 1; i <= len; i++) hb[i] = hb[i-1] * P + (s[i] - 'a' + 1); ans = 1; for (i = 1; i <= len; i++) { l = 1; r = min(i-1,len-i); tmp = 0; while (l <= r) { mid = (l + r) >> 1; if (getha(i-mid,i) == gethb(i,i+mid)) { tmp = mid; l = mid + 1; } else r = mid - 1; } ans = max(ans,2*tmp+1); l = 1; r = min(i,len-i); tmp = 0; while (l <= r) { mid = (l + r) >> 1; if (getha(i-mid+1,i) == gethb(i+1,i+mid)) { tmp = mid; l = mid + 1; } else r = mid - 1; } ans = max(ans,2*tmp); } printf("Case %d: %d\n",++TC,ans); } return 0; }
代码2
/* Algorithm : Manacher Time Complexity : O(TN) */ #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <exception> #include <fstream> #include <functional> #include <limits> #include <list> #include <map> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stdexcept> #include <streambuf> #include <string> #include <utility> #include <vector> #include <cwchar> #include <cwctype> #include <stack> #include <limits.h> using namespace std; #define MAXN 1000010 int TC; char s[MAXN<<1]; inline void Manacher() { int i,len,mx = 0,pos = 0,ans = 0; static char tmp[MAXN<<1]; static int p[MAXN<<1]; len = strlen(s+1); for (i = 1; i <= len; i++) { tmp[2*i-1] = '#'; tmp[2*i] = s[i]; } tmp[len = 2 * len + 1] = '#'; for (i = 1; i <= len; i++) { if (mx > i) p[i] = min(p[2*pos-i],mx-i); else p[i] = 1; while (i - p[i] >= 1 && i + p[i] <= len && tmp[i-p[i]] == tmp[i+p[i]]) p[i]++; if (i + p[i] - 1 > mx) { mx = i + p[i] - 1; pos = i; } } for (i = 1; i <= len; i++) ans = max(ans,p[i]-1); printf("Case %d: %d\n",++TC,ans); } int main() { while (scanf("%s",s+1) != EOF) { if (s[1] == 'E') break; Manacher(); } return 0; }