[Luogu P3649] [BZOJ 3676] [APIO2014]回文串

洛谷传送门
BZOJ传送门

题目描述

给你一个由小写拉丁字母组成的字符串 s s 。我们定义 s 的一个子串的存在值为这个子串在 s s 中出现的次数乘以这个子串的长度。

对于给你的这个字符串 s ,求所有回文子串中的最大存在值。

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

abacaba

输出样例#1:

7

输入样例#2:

www

输出样例#2:

4

说明

【样例解释1】

|s| 表示字符串 s s 的长度。

一个字符串 s1s2s|s| 的子串是一个非空字符串 sisi+1sj s i s i + 1 … s j ,其中 1ij|s| 1 ≤ i ≤ j ≤ | s | 。每个字符串都是自己的子串。

一个字符串被称作回文串当且仅当这个字符串从左往右读和从右往左读都是相同的。

这个样例中,有 7 7 个回文子串 a b b c aba a b a aca a c a bacab b a c a b abacaba a b a c a b a 。他们的存在值分别为 4,2,1,6,3,5,7 4 , 2 , 1 , 6 , 3 , 5 , 7

所以回文子串中最大的存在值为 7 7

第一个子任务共 8 分,满足 1|s|100

第二个子任务共 15 分,满足 1|s|1000 1 ≤ | s | ≤ 1000

第三个子任务共 24 分,满足 1|s|10000 1 ≤ | s | ≤ 10000

第四个子任务共 26 分,满足 1|s|100000 1 ≤ | s | ≤ 100000

第五个子任务共 27 分,满足 1|s|300000 1 ≤ | s | ≤ 300000

解题分析

听说当年这道题的标算是 SAM+Manacher S A M + M a n a c h e r ,而且剧毒…

蒟蒻不会 SAM S A M 只好用 PAM P A M 水过去了…

PAM P A M 板题, 网上很多博客讲的很好, 推荐这一篇(蒟蒻这里就不献丑了…)。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <cmath>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 300050
struct Node
{
    int to[26], cnt, fail, len, num;
}tree[MX << 1];
char buf[MX];
int arr, cur, str[MX], n;
namespace PAM
{
    IN int _new(const int &val)
    {tree[arr].len = val; return arr++;}
    IN void init()
    {
        _new(0), _new(-1);
        n = cur = 0; str[0] = -1;
        tree[0].fail = 1;
    }
    IN int jump(R int now)
    {
        W (str[n - tree[now].len - 1] != str[n]) now = tree[now].fail;
        return now;
    }
    IN void add(R int key)
    {
        key -= 'a'; str[++n] = key;
        int nex = jump(cur);
        if(!tree[nex].to[key])
        {
            int now = _new(tree[nex].len + 2);
            tree[now].fail = tree[jump(tree[nex].fail)].to[key];
            tree[nex].to[key] = now;
            tree[now].num = tree[tree[now].fail].num + 1;
        }
        cur = tree[nex].to[key];
        ++tree[cur].cnt;
    }
    IN long long count()
    {
        long long ans = 0;
        for (R int i = arr - 1; i >= 0; --i)
        tree[tree[i].fail].cnt += tree[i].cnt,
        ans = std::max(ans, 1ll * tree[i].cnt * tree[i].len);
        return ans;
    }
}
int main(void)
{
    scanf("%s", buf + 1);
    PAM::init(); int len = std::strlen(buf + 1);
    for (R int i = 1; i <= len; ++i) PAM::add(buf[i]);
    printf("%lld", PAM::count());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值