[BZOJ3676][APIO2014]回文串(Manacher+SAM)

代码总用时:3h

很简单的一道题,只要意识到Manacher算法的本质(本质不同的回文串的个数是O(n)的),配合后缀自动机或者后缀数组就可以轻松解决。

但这道题调了好久,浪费了很多时间,一是因为后缀自动机模板不熟练,而是Manacher算法流程没有一个清楚的认识。

写代码的时候精力要高度集中,不能因为低级错误耽误时间。

下面是SAM版本的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std;

const int N=600100;
int cnt=1,lst=1,n,tot[N],mx[N],p[N],pos[N],son[N][27],fa[N],f[N][20],q[N],R[N];
ll ans; char s[N],S[N];

void ext(int c,int x){
    int p=lst,np=lst=++cnt; mx[np]=mx[p]+1; R[np]=1; pos[x]=np;
    while (!son[p][c] && p) son[p][c]=np,p=fa[p];
    if (!p) fa[np]=1;
    else{
        int q=son[p][c];
        if (mx[q]==mx[p]+1) fa[np]=q;
        else{
            int nq=++cnt; mx[nq]=mx[p]+1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fa[nq]=fa[q]; fa[q]=fa[np]=nq;
            while (son[p][c]==q && p) son[p][c]=nq,p=fa[p];
        }
    }
}

void pre(){
    rep(i,1,cnt) tot[mx[i]]++;
    rep(i,1,n) tot[i]+=tot[i-1];
    for (int i=cnt; i; i--) q[tot[mx[i]]--]=i;
    for (int i=cnt; i; i--) R[fa[q[i]]]+=R[q[i]];
    rep(i,1,cnt){
        f[i][0]=fa[i];
        rep(j,1,19) f[i][j]=f[f[i][j-1]][j-1];
    }
}

void get(int l,int r){
    l=(l>>1)+(l&1); r>>=1; int x=pos[r];
    for (int i=19; ~i; i--)
        if (mx[f[x][i]]>=r-l+1) x=f[x][i];
    ans=max(ans,1ll*R[x]*(r-l+1));
}

void manacher(){
    int mxlen=0,id;
    rep(i,1,n){
        if (mxlen>i) p[i]=min(mxlen-i,p[2*id-i]);
            else{ p[i]=1; if (S[i]!=‘#‘) get(i,i); }
        while (S[i+p[i]]==S[i-p[i]]) get(i-p[i],i+p[i]),p[i]++;
        if (p[i]+i>mxlen) mxlen=p[i]+i,id=i;
    }
}

int main(){
    freopen("palindromes.in","r",stdin);
    freopen("palindromes.out","w",stdout);
    scanf("%s",s+1); n=strlen(s+1);
    rep(i,1,n) ext(s[i]-‘a‘,i);
    pre(); S[0]=‘$‘; S[1]=‘#‘;
    rep(i,1,n) S[(i<<1)+1]=‘#‘,S[i<<1]=s[i];
    n=(n<<1)+1; manacher(); printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/HocRiser/p/8227465.html

时间: 2024-10-07 03:53:22

[BZOJ3676][APIO2014]回文串(Manacher+SAM)的相关文章

【回文自动机】bzoj3676 [Apio2014]回文串

回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i)代表个数(要最后在fail树上dp一遍方可). 答案直接枚举一遍结点,然后用len(i)*cnt(i),取最大者即可. 回文自动机是非常优越的数据结构,可惜比manacher多一个字符集的空间-- #include<cstdio> #include<cstring> #include

bzoj3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左到右

[APIO2014] [Uoj103] [Bzoj3676] Palindromes回文串 [Manacher,后缀数组]

用Manacher算法枚举回文子串,每次在后缀数组排序后的后缀数组中二分,因为用某一后缀和其他子串分别求匹配的长度,匹配长度在排序后该后缀的两侧具有单调性(匹配长度为min{H[x]|i<=x<=j},所以对于查询min(H[x])用ST表O(n)预处理,O(1)查询即可.Manacher时间复杂度O(n),后缀数组复杂度O(nlogn),总复杂度O(nlogn).注意二分时的边界条件! #include <iostream> #include <cstdio> #in

bzoj3676: [Apio2014]回文串 回文树

回文树的裸题. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=500100; const int INF=1e9+10; struct PalinTree { int ch[maxn][26],f[maxn]; int

bzoj千题计划304:bzoj3676: [Apio2014]回文串

https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300001 char ss[N]; int s[N]; int tot=1,last; int fail[N],len

BZOJ 3676: [Apio2014]回文串 回文串自动机

裸的回文串自动机 3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 504  Solved: 152 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s

【BZOJ 3676】 [Apio2014]回文串

3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 646 Solved: 219 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出

(回文串 Manacher )Girls&#39; research -- hdu -- 3294

http://acm.hdu.edu.cn/showproblem.php?pid=3294 Girls' research Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 3294 Description One day, sailormoon girls are so delighted that they intend to res

bzoj 3676: [Apio2014]回文串 回文自动机

3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,