• Manacher专题


     1、POJ 3974 Palindrome

      题意:求一个长字符串的最长回文子串。

      思路:Manacher模板。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 1000010;
     5 char s[maxn];
     6 char tmp[2 * maxn + 3];
     7 int p[2 * maxn + 2];
     8 int Manacher(char *s,char *tmp,int *p, int &start)
     9 {////s原字符串,tmp转换后的字符串,p记录长度
    10     //char s[maxn];
    11     //char tmp[2 * maxn + 3];
    12     //int p[2 * maxn + 2];
    13     //将所有可能的奇数 / 偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#
    14     int n = strlen(s);
    15     for (int i = 0; i < 2 * n + 2; i++)
    16     {
    17         if (i == 0) tmp[i] = '$';
    18         else if (i % 2) tmp[i] = '#';
    19         else tmp[i] = s[i / 2 - 1];
    20     }
    21     tmp[2 * n + 2] = '';
    22 
    23     memset(p, 0, sizeof(p));
    24 
    25     int len = 2 * n + 2;
    26     int i = 0, mx = 0, id, ans = 1;//id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界,即回文串最右边字符的最大值
    27     start = 0;
    28     for (i = 1; i < len; i++)
    29     {
    30         if (mx > i) p[i] = min(p[2 * id - i], mx - i);//在Len[j]和mx-i中取个小
    31         else p[i] = 1;//如果i>=mx,要从头开始匹配
    32         while(tmp[i + p[i]] == tmp[i - p[i]])p[i]++;
    33         if (p[i] + i > mx) mx = p[i] + i, id = i;//若新计算的回文串右端点位置大于mx,要更新id和mx的值
    34         if (p[i] - 1 > ans)//返回Len[i]中的最大值-1即为原串的最长回文子串额长度 
    35         {
    36             ans = p[i] - 1;
    37             start = (i - (p[i] - 2)) / 2 - 1;
    38         }
    39     }
    40     return ans;
    41 }
    42 
    43 int main()
    44 {
    45     int t = 1;
    46     while (~scanf("%s", s))
    47     {
    48         if (s[0] == 'E')break;
    49         int st = 0;
    50         int ans = Manacher(s, tmp, p, st);
    51         printf("Case %d: %d
    ",t++, ans);
    52     }
    53     return 0;
    54 }
    View Code

    2、HDU 4513 吉哥系列故事――完美队形II

      题意:求最长回文数字子串,且左右向中间递增。

      思路:manacher基础算法上加个判定条件:即向两边延伸的大小限制。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 1000010;
     5 int s[maxn];
     6 int tmp[2 * maxn + 3];
     7 int p[2 * maxn + 2];
     8 int n;
     9 int Manacher(int *s, int *tmp, int *p, int &start)
    10 {////s原字符串,tmp转换后的字符串,p记录长度
    11  //char s[maxn];
    12  //char tmp[2 * maxn + 3];
    13  //int p[2 * maxn + 2];
    14  //将所有可能的奇数 / 偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#
    15     for (int i = 0; i < 2 * n + 2; i++)
    16     {
    17         if (i == 0) tmp[i] = -1;
    18         else if (i % 2) tmp[i] =0;
    19         else tmp[i] = s[i / 2 - 1];
    20     }
    21     //tmp[2 * n + 2] = '';
    22 
    23     memset(p, 0, sizeof(p));
    24 
    25     int len = 2 * n + 2;
    26     int i = 0, mx = 0, id, ans = 1;//id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界,即回文串最右边字符的最大值
    27     start = 0;
    28     for (i = 1; i < len; i++)
    29     {
    30         if (mx > i) p[i] = min(p[2 * id - i], mx - i);//在Len[j]和mx-i中取个小
    31         else p[i] = 1;//如果i>=mx,要从头开始匹配
    32         while (tmp[i + p[i]] == tmp[i - p[i]]&&tmp[i+p[i]]<=tmp[i+p[i]-2])p[i]++;
    33         if (p[i] + i > mx) mx = p[i] + i, id = i;//若新计算的回文串右端点位置大于mx,要更新id和mx的值
    34         if (p[i] - 1 > ans)//返回Len[i]中的最大值-1即为原串的最长回文子串额长度 
    35         {
    36             ans = p[i] - 1;
    37             start = (i - (p[i] - 2)) / 2 - 1;
    38         }
    39     }
    40     return ans;
    41 }
    42 int main()
    43 {
    44     int T;
    45     scanf("%d", &T);
    46     while (T--)
    47     {
    48         scanf("%d", &n);
    49         for (int i = 0; i < n; i++) scanf("%d", &s[i]);
    50         int st;
    51         int ans = Manacher(s, tmp, p, st);
    52         printf("%d
    ", ans);
    53     }
    54 
    55     return 0;
    56 }
    View Code

     3、hdu 3294 Girls' research

      题意:给出一个字符串,然后给出转换字符C(表示C代表真正的‘a’),然后求转换后的字符串的大于等于2的最长回文子串。

      思路:其实可以先求处原字符串的最长回文子串,再转换输出即可。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn = 1000010;
     5 char s[maxn];
     6 char tmp[2 * maxn + 3];
     7 int p[2 * maxn + 2];
     8 int Manacher(char *s, char *tmp, int *p, int &start)
     9 {////s原字符串,tmp转换后的字符串,p记录以tmp[i]为中心的最长回文子串的最右端到tmp[i]的位置的长度
    10  //char s[maxn];
    11  //char tmp[2 * maxn + 3];
    12  //int p[2 * maxn + 2];
    13  //将所有可能的奇数 / 偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#
    14     int n = strlen(s);
    15     for (int i = 0; i < 2 * n + 2; i++)
    16     {
    17         if (i == 0) tmp[i] = '$';
    18         else if (i % 2) tmp[i] = '#';
    19         else tmp[i] = s[i / 2 - 1];
    20     }
    21     tmp[2 * n + 2] = '';
    22 
    23     memset(p, 0, sizeof(p));
    24     int len = 2 * n + 2;
    25     int i = 0, mx = 0, id, ans = 1;//id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界,即回文串最右边字符的最大值
    26     start = 0;
    27     for (i = 1; i < len; i++)
    28     {
    29         if (mx > i) p[i] = min(p[2 * id - i], mx - i);//在Len[j]和mx-i中取个小
    30         else p[i] = 1;//如果i>=mx,要从头开始匹配
    31         while (tmp[i + p[i]] == tmp[i - p[i]])p[i]++;
    32         if (p[i] + i > mx) mx = p[i] + i, id = i;//若新计算的回文串右端点位置大于mx,要更新id和mx的值
    33         if (p[i] - 1 > ans||(p[i]-1==ans&& (i - (p[i] - 2)) / 2 - 1<start))//返回Len[i]中的最大值-1即为原串的最长回文子串额长度 
    34         {
    35             ans = p[i] - 1;
    36             start = (i - (p[i] - 2)) / 2 - 1;
    37         }
    38     }
    39     return ans;
    40 }
    41 
    42 int main()
    43 {
    44     char c;
    45     while (cin>>c)
    46     {
    47         scanf("%s", s);
    48         int st = 0;
    49         int ans = Manacher(s, tmp, p, st);
    50         if (ans >= 2)
    51         {
    52             printf("%d %d
    ", st,st+ans-1);
    53             for (int i = st; i < st + ans; i++)printf("%c", ('a'+s[i]+26-c)>'z'? 'a' + s[i]- c: 'a' + s[i] + 26 - c);
    54             printf("
    ");
    55         }
    56         else printf("No solution!
    ");
    57         
    58     }
    59     return 0;
    60 }
    View Code
  • 相关阅读:
    Linux Ubuntu 忘记用户名和密码 解决办法
    C语言中标准输入流、标准输出流、标准错误输出流
    递归实现字符串反转char* reverse(char* str)合集
    (转)最好的求平方根的方法(精确度VS速度)Best Square Root Method Algorithm Function (Precision VS Speed)
    java验证码识别4
    互聯網產品設計主題詞表
    java验证码识别3
    C++实现C#的get,set属性操作
    简陋,山寨,Everything,桌面搜索,原理,源码
    java验证码识别1
  • 原文地址:https://www.cnblogs.com/ivan-count/p/7421647.html
Copyright © 2020-2023  润新知