Manacher 算法(hdu 3068 && hdu 3294)

  今天打算补前晚 BC 的第二题,发现要用到能在 O(n) 时间求最大回文子串长度的 Manacher 算法,第一次听,于是便去百度了下,看了大半天,总算能看懂了其思想,至于他给出的代码模板我没能完全看懂,只好自己试着实现,发现理解了思想后还是能实现出来的,用自己的风格去写更好理解,先附上讲解 Manacher 算法的几个链接:

  Manacher算法--O(n)回文子串算法 (我就是看这个理解的~)

  Manacher算法处理字符串回文

  hdu3068之manacher算法+详解

  浅谈manacher算法

  hdu 3068 正好是裸题,我便试着写下,我是这样子构造新串的:

  hdu 3068 代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 110005;
 6
 7 // str 为原串, s 为新串
 8 char str[N], s[N << 1];
 9 int p[N << 1];
10 // p[i] 表示以 s[i] 为中心时的回文半径,不包括 p[i]
11 // 即若 s[i - 1] != s[i + 1] 时,p[i] = 0;
12
13 int main() {
14     while(~scanf("%s",str)) {
15         int n = strlen(str);
16         s[0] = ‘$‘;             // 构造新串
17         s[1] = ‘#‘;
18         for(int i = 0; i < n; ++i) {
19             s[i * 2 + 2] = str[i];      // 下标要处理好
20             s[i * 2 + 3] = ‘#‘;
21         }
22         n = n * 2 + 2;             // 更新新串的长度
23         s[n] = ‘\0‘;               // 最后的结束符别忘了
24
25         // right 记录的是在 i 之前的回文串中,某个回文串延伸至最右端的位置
26         // id 就是该回文串的下标(注意都是在新串中的)
27         int right = 0, id = 0;
28         p[0] = 0;
29         // 因为是 s[0] == ‘$‘,作为特殊标记,左右两边都没有相等的,所以初始化为 0,
30         // 同理 right 一开始能延伸到的位置就是 s[0] 的位置,也就是 0,id 当然也为 0
31
32         // 主算法要开始了
33         for(int i = 1; i < n; ++i) {
34             if(right > i)
35                 p[i] = min(p[2 * id - i], right - i);
36             else    p[i] = 0;
37             while(s[i + p[i] + 1] == s[i - p[i] - 1])   ++p[i];
38             if(i + p[i] > right) {
39                 right = i + p[i];
40                 id = i;
41             }
42         }
43
44 //        printf("\n下标: ");
45 //        for(int i = 0; i <= n; ++i)
46 //            printf("%d  ",i);
47 //        puts("");
48 //        printf("新串: ");
49 //        for(int i = 0; i < n; ++i)
50 //            printf("%c  ",s[i]);
51 //        printf(" \\0\np[i]: ");
52 //        for(int i = 0; i < n; ++i)
53 //            printf("%d  ",p[i]);
54 //        puts("");
55
56         int ans = 0;
57         for(int i = 1; i < n; ++i)
58             ans = max(ans, p[i]);       // p[i] 就是原串中的回文长度, 无须作任何 +1、-1
59         printf("%d\n",ans);
60     }
61     return 0;
62 }

  还有一题也是需要用到这个算法的,hdu 3294,只是对于最后的结果输出需要处理一下,恶心的模拟,直接贴代码了:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 200005;
 6
 7 char str[N], s[N << 1];
 8 int p[N << 1];
 9
10 int main() {
11     while(gets(str)) {
12         int n = strlen(str);
13         s[0] = ‘$‘;
14         s[1] = ‘#‘;
15         for(int i = 2; i < n; ++i) {
16             s[i * 2 - 2] = str[i];
17             s[i * 2 - 1] = ‘#‘;
18         }
19         n = n * 2 - 2;
20         s[n] = ‘\0‘;
21
22         int right = 0, id = 0;
23         p[0] = 0;
24         for(int i = 1; i < n; ++i) {
25             if(right > i)
26                 p[i] = min(p[id * 2 - i], right - i);
27             else    p[i] = 0;
28             while(s[i + p[i] + 1] == s[i - p[i] - 1])   ++p[i];
29             if(i + p[i] > right) {
30                 right = i + p[i];
31                 id = i;
32             }
33         }
34         int Max = 0, mid;
35         for(int i = 1; i < n; ++i) {
36             if(p[i] > Max) {
37                 Max = p[i];
38                 mid = i;
39             }
40         }
41         if(Max == 1) {
42             puts("No solution!");
43             continue;
44         }
45
46         int strid = (mid - Max + 1) / 2 + 1;
47         printf("%d %d\n", strid - 2, strid - 2 + Max - 1);
48
49         for(int i = 0; i < Max; ++i) {
50             char ch = str[strid + i] + (‘a‘- str[0]);
51             if(ch < ‘a‘)   ch = ‘z‘ + 1 - (‘a‘ - ch);
52             else if(ch > ‘z‘)   ch = ‘a‘ - 1 + (ch - ‘z‘);
53             printf("%c",ch);
54         }
55         puts("");
56     }
57     return 0;
58 }

时间: 2024-10-23 15:46:57

Manacher 算法(hdu 3068 && hdu 3294)的相关文章

HDU 3068 &amp;&amp;HDU 3294 +最长回文串*3—— manacher/扩展KMP/DP

HDU 3068 http://acm.hdu.edu.cn/showproblem.php?pid=3068 HDU 3294http://acm.hdu.edu.cn/showproblem.php?pid=3294 扩展KMP:https://segmentfault.com/a/1190000008663857 感觉DP相对实现起来更简洁一些,很容易想到,可以用bool dp[i][j]:表示从i到j是否为回文串,然后最长长度用一个变量记录就好 如果dp[i][j]为回文串,那么dp[i

HDU 3068 最长回文 (manacher算法)

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9188    Accepted Submission(s): 3159 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组

HDU 3294 Girls&#39; research (Manacher算法 + 记录区间)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3294 题目大意:输入一个字符ch和一个字符串,问如果把ch当作'a'的话,字符串的每个字符也要做相应变化,如b aa,若b为'a',则b前面的a就为'a'前面的'z',这里是循环表示,输出字符串的最长回文子串,如果最长回文子串串长为1,输出No solution! 几乎是模板题,唯一的特别之处就是要输出回文串字符,所以要记录max(Mp[i])对应的在原串中的字符区间,根据Manacher算法的步骤

hdu 3068 Manacher算法 O(n)回文子串算法

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3068 关于算法的教程  推荐这个:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824    注意:我推荐的这篇博客里说的那个代码有bug,我觉得没问题,而是博主在用的时候写错了,博主举得反例我都过了 而且hdu 3068也过了 最开始是用的后缀数组,2000ms+ 果断超时............... 看过一遍很快就学会这个算法了:然后A

Hdu 3068 最长回文字串Manacher算法

题目链接 最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7976    Accepted Submission(s): 2735 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等 Input 输入

HDU - 3068 最长回文(manacher算法)

题意:给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 分析: manacher算法: 1.将字符串中每个字符的两边都插入一个特殊字符.(此操作的目的是,将字符串长度统一变成奇数,道理很容易想---奇数+偶数=奇数or偶数+奇数=奇数) eg:abba--->#a#b#b#a# 此外,为了便于处理边界,可在字符串开始处再加另外一个特殊字符. eg:#a#b#b#a#--->$#a#b#b#a# 2.数组 P[i] 来记录以字符S[i]为中心的最长回文子串向

hdu 3068 最长回文串 o(n) Manacher 算法

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10596    Accepted Submission(s): 3759 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多

HDU 3068(最长回文-manacher)[Template:manacher]

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9660    Accepted Submission(s): 3353 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组

hdu 3068 最长回文(manacher&amp;最长回文子串)

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7317    Accepted Submission(s): 2500 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组