求一个串的最长回文子串的长度
1.后缀数组
把这个串反转后接到原串的后面,中间连一个没有出现过的字符。
然后求这个新字符串的某两个后缀的公共前缀的最大值即可。
——代码
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 2000010 5 #define max(x, y) ((x) > (y) ? (x) : (y)) 6 7 int n, m, len, ans; 8 int buc[N], x[N], y[N], sa[N], rank[N], height[N]; 9 char s[N]; 10 11 inline void build_sa() 12 { 13 int i, k, p; 14 for(i = 0; i < m; i++) buc[i] = 0; 15 for(i = 0; i < len; i++) buc[x[i] = s[i]]++; 16 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 17 for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i; 18 for(k = 1; k <= len; k <<= 1) 19 { 20 p = 0; 21 for(i = len - 1; i >= len - k; i--) y[p++] = i; 22 for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k; 23 for(i = 0; i < m; i++) buc[i] = 0; 24 for(i = 0; i < len; i++) buc[x[y[i]]]++; 25 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 26 for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i]; 27 std::swap(x, y); 28 p = 1, x[sa[0]] = 0; 29 for(i = 1; i < len; i++) 30 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++; 31 if(p >= len) break; 32 m = p; 33 } 34 } 35 36 inline void build_height() 37 { 38 int i, j, k = 0; 39 for(i = 0; i < len; i++) rank[sa[i]] = i; 40 for(i = 0; i < len; i++) 41 { 42 if(!rank[i]) continue; 43 if(k) k--; 44 j = sa[rank[i] - 1]; 45 while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++; 46 height[rank[i]] = k; 47 } 48 } 49 50 int main() 51 { 52 int i, k, tot = 0; 53 while(scanf("%s", s)) 54 { 55 if(s[0] == 'E' && s[1] == 'N' && s[2] == 'D') break; 56 tot++; 57 ans = 0; 58 m = 256; 59 k = strlen(s); 60 s[k] = '#'; 61 for(i = 0; i < k; i++) s[k + i + 1] = s[k - i - 1]; 62 len = k << 1 | 1; 63 build_sa(); 64 build_height(); 65 for(i = 1; i < len; i++) 66 if((sa[i - 1] < k && sa[i] > k) || (sa[i - 1] > k && sa[i] < k)) 67 ans = max(ans, height[i]); 68 printf("Case %d: %d ", tot, ans); 69 } 70 return 0; 71 }
2.manacher
#include <cstdio> #include <cstring> #define N 2100000 #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) int p[N]; char s[N]; int n, pos, maxright, ans; int main() { int i, cnt = 0;; while(scanf("%s", s + 1) && s[1] != 'E') { cnt++; n = strlen(s + 1); s[0] = '$', s[n * 2 + 1] = '#'; for(i = n; i >= 1; i--) s[i * 2] = s[i], s[i * 2 - 1] = '#'; n *= 2; pos = 1, maxright = 0, ans = 0; for(i = 1; i <= n; i++) { p[i] = 1; if(i <= maxright) p[i] = min(p[pos * 2 - i], maxright - i + 1); while(s[i - p[i]] == s[i + p[i]]) p[i]++; if(maxright < i + p[i] - 1) { pos = i; maxright = i + p[i] - 1; } ans = max(ans, p[i] - 1); } printf("Case %d: %d ", cnt, ans); } return 0; }