• 初涉manacher


    一直没有打过……那么今天来找几道题打一打吧

    manacher有什么用

    字符串的题有一类是专门关于“回文”的。通常来说,这类问题要么和一些dp结合在一起;要么是考察对于manacher(或其他如回文自动机)的理解。

    裸的manacher则是解决形如“一个字符串内最长回文串长度”的问题。

    一些例题

    luoguP3805 【模板】manacher算法

    题目描述

    给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.

    字符串长度为n

    输入输出格式

    输入格式:

    一行小写英文字符a,b,c...y,z组成的字符串S

    输出格式:

    一个整数表示答案

    输入输出样例

    输入样例#1:
    aaa
    输出样例#1:
    3

    说明

    字符串长度len <= 11000000


    题目分析

    注意f[maxn<<1]

     1 #include<bits/stdc++.h>
     2 const int maxn = 11000035;
     3 
     4 int n,f[maxn<<1],mid,ans;
     5 char s[maxn],t[maxn<<1];
     6 
     7 int main()
     8 {
     9     scanf("%s",s+1), t[0] = '!', t[++n] = '#';
    10     for (int i=1; s[i]; i++) t[++n] = s[i], t[++n] = '#';
    11     for (int i=1, mx=-1; i<n; i++)
    12     {
    13         if (i < mx) f[i] = std::min(f[(mid<<1)-i], mx-i);
    14         else f[i] = 1;
    15         for (; t[i+f[i]]==t[i-f[i]]; f[i]++);
    16         if (i+f[i] > mx) mx = i+f[i], mid = i;
    17         ans = f[i] > ans?f[i]:ans;
    18     }
    19     printf("%d
    ",ans-1);
    20     return 0;
    21 }

    bzoj2565: 最长双回文串

    Description

    顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
    输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。

    Input

    一行由小写英文字母组成的字符串S

    Output

    一行一个整数,表示最长双回文子串的长度。

    Sample Input

    baacaabbacabb

    Sample Output

    12

    HINT

    样例说明
    从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
    对于100%的数据,2≤|S|≤10^5


    题目分析

    枚举断点,并处理出每一个位置所能够作为起点扩展出的最远位置。

    有一些挺好的细节:【BZOJ2565】最长双回文串 Manacher

     1 #include<bits/stdc++.h>
     2 const int maxn = 100035;
     3 
     4 int n,ans,mid,f[maxn<<1],ls[maxn<<1],rs[maxn<<2];
     5 char s[maxn],t[maxn<<1];
     6 
     7 inline void Max(int &x, int y){x = x>y?x:y;}
     8 int main()
     9 {
    10     scanf("%s",s+1), t[0] = '!', t[++n] = '#';
    11     for (int i=1; s[i]; i++) t[++n] = s[i], t[++n] = '#';
    12     for (int i=1, mx=-1; i<=n; i++)
    13     {
    14         if (i < mx) f[i] = std::min(f[(mid<<1)-i], mx-i);
    15         else f[i] = 1;
    16         for (; t[i-f[i]]==t[i+f[i]]; f[i]++);
    17         if (i+f[i] > mx) mx = i+f[i], mid = i;
    18         Max(rs[i-f[i]+1], f[i]-1);
    19         Max(ls[i+f[i]-1], f[i]-1);
    20     }
    21     for (int i=3; i<=n; i+=2) Max(rs[i], rs[i-2]-2);
    22     for (int i=n; i>=1; i-=2) Max(ls[i], ls[i+2]-2);
    23     for (int i=1; i<=n; i+=2)
    24         if (ls[i]&&rs[i]) ans = std::max(ans, ls[i]+rs[i]);
    25     printf("%d
    ",ans);
    26     return 0;
    27 }

    bzoj3790: 神奇项链

    Description

    母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
    母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。 

    Input

    输入数据有多行,每行一个字符串,表示目标项链的样式。 

    Output

    多行,每行一个答案表示最少需要使用第二个机器的次数。 

    Sample Input

    abcdcba
    abacada
    abcdef

    Sample Output

    0
    2
    5

    HINT

    每个测试数据,输入不超过 5行 
    每行的字符串长度小于等于 50000 

    题目分析

    沿用上一题的做法,manacher预处理出最远扩展到的位置。之后就是一个贪心的向远处跳的过程。

    (好像预处理暴力也行?)

    也挺妙的:【BZOJ3790】神奇项链 Manacher+贪心

     1 #include<bits/stdc++.h>
     2 const int maxn = 50003;
     3 
     4 int n,ans,mid,now,nxt,f[maxn<<1],rs[maxn<<1];
     5 char s[maxn],t[maxn<<1];
     6 
     7 int main()
     8 {
     9     while (scanf("%s",s+1)!=EOF)
    10     {
    11         memset(f, 0, sizeof f);
    12         ans = n = 0, t[0] = '!', t[++n] = '#';
    13         for (int i=1; s[i]; i++) t[++n] = s[i], t[++n] = '#';
    14         for (int i=1, mx=-1; i<n; i++)
    15         {
    16             if (i < mx) f[i] = std::min(f[(mid<<1)-i], mx-i);
    17             else f[i] = 1;
    18             for (; t[i+f[i]]==t[i-f[i]]; f[i]++);
    19             if (i+f[i] > mx) mx = i+f[i]-1, mid = i;
    20             rs[i-f[i]+1] = i+f[i]-1;
    21         }
    22 //        now = 1, nxt = 0;
    23 //        while (rs[now] < n)
    24 //        {
    25 //            for (int i=now+1; i<=rs[now]; i++)
    26 //                if (rs[i] > rs[nxt]) nxt = i;
    27 //            ans++, now = nxt;
    28 //        }    //这种是不是不行啊……?
    29         now = nxt = rs[1]+2;
    30         for (int i=1; i<=n; i+=2)
    31         {
    32             if (i==now) now = nxt, ans++;
    33             nxt = std::max(nxt, rs[i]+2);
    34         }
    35         printf("%d
    ",ans);
    36     }
    37     return 0;
    38 }

    END

  • 相关阅读:
    重载和重写的定义
    方法的重载与重写有什么区别?
    java: while 和do while区别
    java中的运算符
    java 8种基本数据类型
    java.面向对象特征
    java语言的特点
    java.注释类型
    char 和 varchar2 区别
    使用sql对数据库进行简单的增删改查
  • 原文地址:https://www.cnblogs.com/antiquality/p/9820621.html
Copyright © 2020-2023  润新知