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

传送门

这道题显然可以用PAM做出来。

PAM可以算出以字符串的第ii个字符为结尾的回文子串的个数。我们将其存到一个数组l[n],再求一个前缀和就可以把字符串的前i个字符的前缀有多少个回文子串求出来。

然后,我们将PAM清空,倒着做一遍,就可以求出以第i个字符为左端点的回文子串个数r[i]。与它不相交的回文子串且在它前面的子串有l[i - 1]个,相乘再累加就是答案。

此题在落谷的评级是绿,那是因为此题数据范围只有2000,不用PAM也可以做。但此题可以当做PAM入门的练手题。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int N = 200000;
struct Plalindromic_Tree{
    int go[26], len, fail;
    ll fail_len;
}pt[N];
int lst, tot;
char s[N], ss[N];
void build() {
    lst = tot = 0;
    ss[0] = -1;
    pt[++tot].len = -1;
    pt[0].fail = pt[1].fail = 1;
    pt[0].fail_len = 2;
    pt[1].fail_len = 1;
}
int add(int c, int n) {
    int p = lst;
    ss[n] = c + ‘a‘;
    while (ss[n - pt[p].len - 1] != ss[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 (ss[n - pt[k].len - 1] != ss[n]) k = pt[k].fail;
        pt[v].fail = pt[k].go[c];
        pt[v].fail_len = pt[pt[v].fail].fail_len + 1;
        pt[p].go[c] = v;
    }
    return lst = pt[p].go[c];
}
ll r[N], ans;
int lens;
int main() {
    scanf("%s", s + 1);
    lens = strlen(s + 1);
    build();
    for (int i = 1; i <= lens; i++) {
        r[i] = (pt[add(s[i] - ‘a‘, i)].fail_len - 2) + r[i - 1];
    }
//    cout<< endl;
    memset(pt, 0, sizeof(pt));
    build();
    for (int i = lens; i > 1; i--) {
        ans += (pt[add(s[i] - ‘a‘, lens - i + 1)].fail_len - 2) * r[i - 1];
    }
    cout << ans;
    return 0;
}

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

时间: 2024-10-09 16:04:27

落谷P1872 回文串计数(回文树)的相关文章

P1872 回文串计数(回文树)

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

【NOIP模拟赛】【乱搞AC】【奇技淫巧】【乘法原理】回文串计数

回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他走向了以记忆量大而闻名的生物竞赛.然而,他很快发现这并不能满足他热爱背诵的心,但是作为一名强大的Boer,他找到了这么一条自虐的方式--背诵基因序列.不过这实在是太虐心了,就连Mcx也有些招架不住.不过他发现,如果他能事先知道这个序列里有多少对互不相交的回文串,他或许可以找到记忆的妙法.为了进一步验证这个方法,M

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 说明 [样例解

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,&

回文串[APIO2014](回文树)

题目描述 给你一个由小写拉丁字母组成的字符串 s.我们定义 s 的一个子串的存在值为这个子串在 s中出现的次数乘以这个子串的长度.对于给你的这个字符串 s,求所有回文子串中的最大存在值. 输入格式 一行,一个由小写拉丁字母(a~z)组成的非空字符串 s. 输出格式 输出一个整数,表示所有回文子串中的最大存在值. 样例 输入样例 1 abacaba 输出样例 1 7 输入样例 2 www 输出样例 2 4 首先建出s的回文树,然后对于每一个回文子串,记录cnt为它出现的次数. 对于它fail树上的

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

LeetCode 5 迅速判断回文串的曼切斯特算法

题意 Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Link: https://leetcode.com/problems/longest-palindromic-substring/ 翻译 给定一个字符串s,要求它当中的最长回文子串.可以假设s串的长度最大是1000. 样例 Example 1: Input:

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

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