【BZOJ】3676 [Apio2014]回文串

【算法】回文树

【题解】建回文数,然后一个回文子串出现的次数就是结点被访问的次数以及能包含它的结点被访问的次数。

根据fail树反向建新树,那么答案就是结点所在子树的权值和(权值就是结点被访问次数)。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=300010;
char s[maxn];
int n,len,l,sz,first[maxn],tot;
long long ans;
struct trees{int len,fail,t[30],num;}t[maxn];
struct edges{int v,from;}e[maxn*3];
void insert(int u,int v)
{tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
int getfail(int x)
{
    while(s[len-t[x].len-1]!=s[len])x=t[x].fail;
    return x;
}
void tree_work()
{
    int x=s[++len]-‘a‘;
    l=getfail(l);
    if(!t[l].t[x])
    {
        sz++;
        t[sz].len=t[l].len+2;
        t[sz].num=1;
        t[sz].fail=t[getfail(t[l].fail)].t[x];//偏小
        insert(t[sz].fail,sz);
        t[l].t[x]=sz;
    }
    else
    {
        t[t[l].t[x]].num++;
    }
    l=t[l].t[x];
}
long long dfs(int x)
{
    long long sum=t[x].num;
    for(int i=first[x];i;i=e[i].from)
    {
        sum+=dfs(e[i].v);
    }
    ans=max(ans,1ll*t[x].len*sum);
    return sum;
}
int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    sz=1;
    s[0]=-1;//
    t[0].len=0;t[1].len=-1;
    t[0].fail=t[1].fail=1;
    t[0].num=t[1].num=1;
    insert(1,0);
    len=l=ans=0;
    for(int i=1;i<=n;i++)tree_work();
    dfs(1);
    printf("%lld",ans);
    return 0;
}

时间: 2024-08-04 11:11:43

【BZOJ】3676 [Apio2014]回文串的相关文章

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

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [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 一个串是回文的,当且仅当它从左

BZOJ 3676 [Apio2014]回文串(回文树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题目大意] 考虑一个只包含小写拉丁字母的字符串s. 我们定义s的一个子串t的"出现值"为t在s中的出现次数乘以t的长度. 求s的所有回文子串中的最大出现值. [题解] 我们对给出串建立回文树,统计每个回文串出现次数和长度,相乘取组大即可 [代码] #include <cstdio> #include <algorithm> #include

bzoj 3676: [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 一个串是回文的,当且

bzoj 3676 [Apio2014]回文串(Manacher+SAM)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题意] 给定一个字符串,定义一个串的权值为长度*出现次数,求最大权的回文子串. [思路] 马拉车求出本质不同的回文子串. 对于一个回文子串,在SAM中用倍增法在O(logn)的时间得到它的出现次数,即SAM中每个节点的right集大小,倍增数组和right都可以通过提前处理得到. 更新答案即可. [代码] 1 #include<set> 2 #include<cmat

BZOJ 3676: [Apio2014]回文串 后缀自动机 Manacher 倍增

http://www.lydsy.com/JudgeOnline/problem.php?id=3676 过程很艰难了,第一次提交Manacher忘了更新p数组,超时,第二次是倍增的第0维直接在自动机里完成,但是忽略了增加新点时fa变动的情况,还是肉眼查错最管用. 得到的教训是既然倍增就在倍增的函数里完成,自动机就在自动机里完成,不要随便乱搞赋值. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm>

【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 输出

【回文自动机】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