回文串[APIO2014](回文树)

题目描述

给你一个由小写拉丁字母组成的字符串 s。我们定义 s 的一个子串的存在值为这个子串在 s中出现的次数乘以这个子串的长度。对于给你的这个字符串 s,求所有回文子串中的最大存在值。

输入格式

一行,一个由小写拉丁字母(a~z)组成的非空字符串 s。

输出格式

输出一个整数,表示所有回文子串中的最大存在值。

样例

输入样例 1

abacaba

输出样例 1

7

输入样例 2

www

输出样例 2

4

首先建出s的回文树,然后对于每一个回文子串,记录cnt为它出现的次数。

对于它fail树上的儿子,肯定都是它的子串(后缀),所以他出现了cnt次,它的后缀也会出现cnt次。

我们从更新的节点从后往前遍历,假设现在遍历到i,就使cnt[fail[i]]+=cnt[i]。然后更新ans=max(ans, cnt[i]*len[i])。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 400000;
char s[N];
int lens;
long long ans;
namespace Plalindromic_Tree{
    struct node{
        int go[26];
        int fail, len;
    }pt[N];
    int lst = 0, tot = 0;
    int cnt[N];
    void build() {
        s[0] = -1;
        pt[++tot].len = -1;
        pt[0].fail = pt[1].fail = 1;
    }
    void add(int c, int n) {
        int p = lst;
        while (s[n - pt[p].len - 1] != s[n]) p = pt[p].fail;
        if (!pt[p].go[c]) {
            int v = ++tot, k = pt[p].fail;
            pt[v].len = pt[p].len + 2;
            while (s[n - pt[k].len - 1] != s[n]) k = pt[k].fail;
            pt[v].fail = pt[k].go[c];
            pt[p].go[c] = v;
        }
        lst = pt[p].go[c];
        cnt[pt[p].go[c]]++;
    }
}using namespace Plalindromic_Tree;
int main() {
    scanf("%s", s + 1);
    lens = strlen(s + 1);
    build();
    for (int i = 1; i <= lens; i++) {
        add(s[i] - ‘a‘, i);
    }
    for (int i = tot; i; i--) {
        cnt[pt[i].fail] += cnt[i];
        ans = max(ans, 1ll * cnt[i] * pt[i].len);
    }
    cout << ans;
    return 0;
}
 

原文地址:https://www.cnblogs.com/zcr-blog/p/12298869.html

时间: 2024-08-30 17:23:32

回文串[APIO2014](回文树)的相关文章

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

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

P3649 [APIO2014]回文串(回文树)

题目描述 给你一个由小写拉丁字母组成的字符串 ss .我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 ss ,求所有回文子串中的最大存在值. 输入输出格式 输入格式: 一行,一个由小写拉丁字母(a~z)组成的非空字符串 ss . 输出格式: 输出一个整数,表示所有回文子串中的最大存在值. 输入输出样例 输入样例#1: 复制 abacaba 输出样例#1: 复制 7 输入样例#2: 复制 www 输出样例#2: 复制 4 说明 [样例解

P1872 回文串计数(回文树)

题目描述 小a虽然是一名理科生,但他常常称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名其妙的热爱,这也促使他走向了以记忆量大而闻名的生物竞赛.然而,他很快发现这并不能满足他热爱背诵的心,但是作为一名强大的OIER,他找到了这么一个方法--背诵基因序列.然而这实在是太困难了,小啊感觉有些招架不住.不过他发现,如果他能事先知道这个序列里有多少对互不相交的回文串,他或许可以找到记忆的妙法.为了进一步验证这个想法,小a决定选取一个由小写字母构成的字符串SS来实验.由于互不相关的回文串实在过多

P3649 [APIO2014]回文串(回文自动机)

回文自动机裸题,把PAM建出来以后对每个节点更新答案即可 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&b) #define sccc(a,b,c) scanf("%lld %lld %lld",&a,&

落谷P1872 回文串计数(回文树)

传送门 这道题显然可以用PAM做出来. PAM可以算出以字符串的第ii个字符为结尾的回文子串的个数.我们将其存到一个数组l[n],再求一个前缀和就可以把字符串的前i个字符的前缀有多少个回文子串求出来. 然后,我们将PAM清空,倒着做一遍,就可以求出以第i个字符为左端点的回文子串个数r[i].与它不相交的回文子串且在它前面的子串有l[i - 1]个,相乘再累加就是答案. 此题在落谷的评级是绿,那是因为此题数据范围只有2000,不用PAM也可以做.但此题可以当做PAM入门的练手题. #include

BZOJ2565: 最长双回文串(回文树)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2565 记录一下每个点往前最长延伸位置,正反两遍,枚举分割点. #include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int

BZOJ 3676 【APIO2014】 回文串

题目链接:回文串 我终于也会回文自动机辣! 其实吗--我觉得回文自动机(听说这玩意儿叫\(PAM\))还是比较\(simple\)的--至少比\(SAM\)友善多了-- 所谓回文自动机,每个节点就代表一个回文串.回文自动机的每个节点有两个东西,一个是\(next\),一个是\(fail\).\(next_{u,x}\)指向节点\(u\)所代表的回文串在两端各添加一个字符\(x\)得到一个新的回文串.\(fail_u\)则指向\(u\)这个节点的最长后缀回文串(不包括本身).当然还有一个\(len

Openjudge-计算概论(A)-回文串判断

描述: 任意给定一个非空的字符串,判断其是否是回文串.回文串是指正向看和反向看均相等的串,如AbcDcbA和cDDc.如果是回文串,则输出1,否则,输出0 输入长度不小于1不大于100的字符串输出如果是回文串,输出1如果不是回文串,输出0 样例输入 abcdefghijkjihgfedcba 样例输出 1思路:这题很简单,算是字符串入门题,只要判断是否从前往后扫和从后往前扫一样就得了,输出.提示:这题输入一定要用gets()函数,否则会报错代码如下: 1 #include<stdio.h> 2

回文串

[问题描述] 操作包含两个步骤:第一步:写一个很长的字符串(只包含小写)在纸上.例如,"abcde",而是'a'里面是不是真正的'a',这意味着如果我们定义的'b'才是真正的'a',那么我们可以推断,'c'才是真正的'b' ,'d'才是真正的'c'......,'a'才是真正的'z'.根据这一点,字符串"abcde"变为"bcdef".第二步:找出给定字符串中最长的回文串,回文字符串的长度必须等于或超过2. [输入描述] 输入包含多个样例.每个样