【XSY2534】【CF835D】Palindromic characteristics 回文自动机

题目大意

?  一个字符串\(s\)是\(1\)?回文串当且仅当这个串是回文串。

?  一个串\(s\)是\(k\)?回文串\((k>1)\)当且仅当\(s\)的前一半与后一半相同且\(s\)的前一半是非空\((k?1)\)?回文串。

?  一个串\(s\)的前一半是这个串的长度为\(\lfloor\frac{|s|}{2}\rfloor\)的前缀,一个串\(s\)的后一半是这个串的长度为\(\lfloor\frac{|s|}{2}\rfloor\)的后缀

?  有一个字符串\(s\),对于每个\(k\in\{1\ldots n\}\),求出\(s\)的多少个子串是\(k\)?回文串。

?  原题:\(1\leq n\leq 5000\)

?  加强版:\(1\leq n\leq 1000000\)

题解

?  我们可以发现,一个串是\(k\)-回文串,那么这个串就是\((k-1)\)-回文串\((k>1)\)

?  所以可以DP:设\(f_{i,j}\)表示\(s_{i\ldots j}\)最高是几阶回文串

?  时间复杂度:\(O(n^2)\)

?  我们还可以用BZOJ4044那道题的方法,在回文自动机上处理出每个串的长度不超过这个串长一半的最长回文后缀,然后直接转移即可

?  时间复杂度:\(O(n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
int nxt[1000010][30];
int fail[1000010];
int len[1000010];
int trans[1000010];
int a[1000010];
int f[1000010];
int cnt[1000010];
ll ans[1000010];
int p;
int n;
int last;
void init(int x)
{
    int i;
    for(i=1;i<=26;i++)
        nxt[x][i]=2;
}
void add(int x)
{
    a[++n]=x;
    while(a[n-len[last]-1]!=a[n])
        last=fail[last];
    int cur=last;
    if(nxt[cur][x]==2)
    {
        int now=++p;
        init(p);
        len[now]=len[cur]+2;
        last=fail[last];
        while(a[n-len[last]-1]!=a[n])
            last=fail[last];
        fail[now]=nxt[last][x];
        if(len[fail[now]]<=len[now]/2)//没有这部分也可以AC
            trans[now]=fail[now];
        else
        {
            last=trans[cur];
            while(len[last]+2>len[now]/2||a[n-len[last]-1]!=a[n])
                last=fail[last];
            trans[now]=nxt[last][x];
        }
        nxt[cur][x]=now;
    }
    last=nxt[cur][x];
    cnt[last]++;
}
void solve()
{
    f[1]=0;
    f[2]=0;
    int i;
    for(i=3;i<=p;i++)
        if(len[trans[i]]==len[i]/2)
            f[i]=f[trans[i]]+1;
        else
            f[i]=1;
    for(i=p;i>=3;i--)
        cnt[fail[i]]+=cnt[i];
    for(i=3;i<=p;i++)
        ans[f[i]]+=cnt[i];
}
char s[1000010];
int main()
{
//  freopen("necklace.in","r",stdin);
//  freopen("necklace.out","w",stdout);
    p=0;
    n=0;
    init(++p);
    fail[p]=2;
    len[p]=-1;
    trans[p]=2;
    init(++p);
    fail[p]=1;
    len[p]=0;
    a[0]=-1;
    trans[p]=1;
    last=p;
    int m;
    scanf("%s",s+1);
    m=strlen(s+1);
    int i;
    for(i=1;i<=m;i++)
        add(s[i]-‘a‘+1);
    solve();
    for(i=m-1;i>=1;i--)
        ans[i]+=ans[i+1];
    for(i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/ywwyww/p/8510044.html

时间: 2024-11-06 07:16:58

【XSY2534】【CF835D】Palindromic characteristics 回文自动机的相关文章

[加强版] Codeforces 835D Palindromic characteristics (回文自动机、DP)

题目链接: https://codeforces.com/contest/835/problem/D 题意: 一个回文串是\(1\)-回文的,如果一个回文串的左半部分和右半部分一样且都是\(k\)-回文串(右半部分是指长度为该串长度除以二下取整的后缀),则该串为\((k+1)\)回文串,满足该串是\(k\)回文串的最大\(k\)称作该串的回文级别.给定一个串\(s\), 对于每一个\(k=1,2,...,n\)求出该串中有多少个位置不同的\(k\)-回文串.\(n\le 5\times 10^6

Palindromic Tree 回文自动机-回文树 例题+讲解

---恢复内容开始--- 回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同回文串包含的本质不同回文串种类 (本文参考自Palindromic Tree——回文树[处理一类回文串问题的强力工具],Palindromic Tree 回文自动机-回文树 解决回文串的神器) 下面介绍一些数组的意义 next[][]类似于字典树,指向当前字符串在两段同时加

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

回文树或者回文自动机,及相关例题

回文树简述 在大部分说法中,回文树与回文自动机指的是一个东西: 回文树是对一个字符串,基于自动机思想构建的处理回文问题的树形结构: 回文树是对着一个单串建立的: 于是他主要用于计数(回文子串种类及个数) 基本建立思路是先建立其前缀的回文树,然后每加上一个字符,统计影响: 回文树存在fail指针但一般不承接字符串匹配问题: (回文树大概可以判定一个回文串是不是一个串的子串,但KMP之类的可以做得更好) 构建好的回文树,是这样的: (好难看) 可看出: 存在两个树结构,分别记录奇数|偶数长度的回文:

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

题目描述 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最大出现值. 输入 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. 输出 输出一个整数,为逝查回文子串的最大出现值. 样例输入 [样例输入l] abacaba [样例输入2] www 样例输出 [样例输出l] 7 [样例输出2] 4 题解 回文自动机裸题 关于PAM个人暂时理解不是很深入,挖坑待填. 本题只需要统计fail树的子树大小,再

[BZOJ4044]Virus synthesis 回文自动机的DP

4044: [Cerc2014] Virus synthesis Time Limit: 20 Sec  Memory Limit: 128 MB Description Viruses are usually bad for your health. How about fighting them with... other viruses? In this problem, you need to find out how to synthesize such good viruses. W

【CF932G】Palindrome Partition 回文自动机

[CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_{k-1}...x_i=x{k-i+1}$. $|s|\le 10^6$ 题解:设字符串的长度为n,考虑字符串$T=s_1s_ns_2s_{n-1}...$.问题就转化成了:求将原串划分成若干个长度为偶数的回文子串的方案数. 首先我们有一种暴力的想法,设f[i]表示将前i个字符分成若干个回文子串的方

【XSY2715】回文串 树链剖分 回文自动机

题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(transl~l_1~r_1~l_2~r_2\):有两个\(s\)的子串\(s_1=s[l_1\ldots r_1],s_2=s[l_2\ldots r_2]\).你要把\(s_1\)变成\(s_2\).每次允许在左边加一个字符或删一个字符.要求操作次数最少.定义一个字符串是好的当且仅当这个字符串是回文串

WHU 583 Palindrome ( 回文自动机 &amp;&amp; 本质不同的回文串的个数 )

题目链接 题意 : 给你一个串.要你将其划分成两个串.使得左边的串的本质不同回文子串的个数是右边串的两倍.对于每一个这样子的划分.其对答案的贡献就是左边串的长度.现在要你找出所有这样子的划分.并将贡献乘起来.答案 mod 1e9+7 分析 : 从左到右跑一边回文自动机.对于每个前缀 能够得出其有多少个本质不同的回文子串 本质不同的回文子串的个数实际上就是自动机节点数 - 2 那么跑一遍前缀之后我们能得到所有可作为左边部分串的本质不同回文子串的个数 因为是回文串.所以我们倒着跑一遍.就同样能得到作