[POJ3974]Palindrome(后缀数组 || manacher)

传送门

 

求一个串的最长回文子串的长度

 

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\n", tot, ans);
69     }
70     return 0;
71 }
View Code

 

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\n", cnt, ans);
	}
	return 0;
} 

  

posted @ 2017-06-12 10:01  zht467  阅读(167)  评论(0编辑  收藏  举报