目的:类似回文Trie树+ac自动机,可以用来统计一些其他的回文串相关的量

复杂度:O(nlogn)

https://blog.csdn.net/Lolierl/article/details/99971257

https://www.luogu.org/problem/P5496

求出以每个位置结尾的回文子串个数,强制在线

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2e6+;
struct pam_trie
{
int ch[];
int fail,len,num;
};
struct pam
{
pam_trie b[maxn];
int n,length,last,cnt,s[maxn];
char c[maxn];
pam()
{
b[].len=;b[].len=-;
b[].fail=;b[].fail=;
last=;
cnt=;
}
void read()
{
scanf("%s",c+);
length=strlen(c+);
}
int get_fail(int x)
{
while(s[n-b[x].len-]!=s[n])x=b[x].fail;
return x;
}
void insert()
{
int p=get_fail(last);
if(!b[p].ch[s[n]])
{
b[++cnt].len=b[p].len+;
b[cnt].fail=b[get_fail(b[p].fail)].ch[s[n]];
//b[cnt].num=b[b[cnt].fail].num+1;
b[p].ch[s[n]]=cnt;
}
last=b[p].ch[s[n]];
b[last].num=b[b[last].fail].num+;
}
void solve()
{
int k=;
s[]=;
for(n=;n<=length;n++)
{
c[n]=(c[n]-+k)%+;
s[n]=c[n]-'a';
insert();
printf("%d ",b[last].num);
k=b[last].num;
}
}
}P; int main()
{
P.read();
P.solve();
return ;
}

https://www.luogu.org/problem/P3649

求回文子串出现次数*长度的最大值

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=3e5+;
struct pam_trie
{
int ch[];
int fail,len,sum;
};
struct pam
{
pam_trie b[maxn];
int n,length,last,cnt,s[maxn];
char c[maxn];
long long ans;
pam()
{
b[].len=;b[].len=-;
b[].fail=;b[].fail=;
last=;
cnt=;
}
void read()
{
scanf("%s",c+);
length=strlen(c+);
}
int get_fail(int x)
{
while(s[n-b[x].len-]!=s[n])x=b[x].fail;
return x;
}
void insert()
{
int p=get_fail(last);
if(!b[p].ch[s[n]])
{
b[++cnt].len=b[p].len+;
b[cnt].fail=b[get_fail(b[p].fail)].ch[s[n]];
b[p].ch[s[n]]=cnt;
}
last=b[p].ch[s[n]];
b[last].sum++;
}
void solve()
{
s[]=;
for(n=;n<=length;n++)
{
s[n]=c[n]-'a';
insert();
}
ans=;
for(int i=cnt;i>;i--)
{
b[b[i].fail].sum+=b[i].sum;
ans=max(ans,1ll*b[i].sum*b[i].len);
}
printf("%lld\n",ans);
}
}P;
int main()
{
P.read();
P.solve();
}

https://www.luogu.org/problem/P4287

计算串的最长双倍回文子串的长度,tips:fail指针指向当前节点所表示的回文串的最长回文后缀

#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=5e5+;
struct pam_trie
{
int ch[];
int fail,len,sum;
};
struct pam
{
pam_trie b[maxn];
int n,length,last,cnt,s[maxn];
char c[maxn];
pam()
{
b[].len=;b[].len=-;
b[].fail=;b[].fail=;
last=;cnt=;
}
void read()
{
scanf("%d",&length);
scanf("%s",c+);
}
int get_fail(int x)
{
while(s[n-b[x].len-]!=s[n])x=b[x].fail;
return x;
}
void insert()
{
int p=get_fail(last);
if(!b[p].ch[s[n]])
{
b[++cnt].len=b[p].len+;
b[cnt].fail=b[get_fail(b[p].fail)].ch[s[n]];
b[p].ch[s[n]]=cnt;
}
last=b[p].ch[s[n]];
b[last].sum++;
}
void solve()
{
s[]=;
for(n=;n<=length;n++)
{
s[n]=c[n]-'a';
insert();
}
int ans=;
for(int i=cnt;i>;i--)
{
int pos=i;
if(b[i].len%!=||b[i].len<=ans)continue;
while(*b[pos].len>b[i].len)pos=b[pos].fail;
if(*b[pos].len==b[i].len)ans=b[i].len;
}
printf("%d\n",ans);
}
}P;
int main()
{
P.read();
P.solve();
return ;
}

ICPC 2018 南京 Mediocre String Problem,用回文自动机来求出以每个位置结尾的回文子串个数,再进行exkmp

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e6+;
struct pam_trie
{
int ch[];
int fail,len,num;
};
int res[maxn];
char s1[maxn],s2[maxn],t[maxn]; struct pam
{
pam_trie b[maxn];
int n,last,cnt,s[maxn],length;
pam()
{
b[].len=;b[].len=-;
b[].fail=;b[].fail=;
last=;
cnt=;
}
int get_fail(int x)
{
while(s[n-b[x].len-]!=s[n])x=b[x].fail;
return x;
}
int insert()
{
int p=get_fail(last);
if(!b[p].ch[s[n]])
{
b[++cnt].len=b[p].len+;
b[cnt].fail=b[get_fail(b[p].fail)].ch[s[n]];
b[p].ch[s[n]]=cnt;
}
last=b[p].ch[s[n]];
b[last].num=b[b[last].fail].num+;
return b[last].num;
}
void solve()
{
s[]=;
length=strlen(s1);
for(n=;n<=length;n++)
{
s[n]=s1[n-]-'a';
res[n-]=insert();
}
}
}P; int Next[maxn],extend[maxn];
void get_next(char *s)
{
int n=strlen(s),i,j,k=;
for(j=;+j<n&&s[j]==s[+j];j++);
Next[]=j;
for(i=;i<n;i++)
{
int len=k+Next[k],L=Next[i-k];
if(L<len-i)Next[i]=L;
else
{
for(j=max(,len-i);i+j<n&&s[j]==s[i+j];j++);
Next[i]=j;
k=i;
}
}
Next[]=n;
}
void ex_kmp(char *T,char *s)
{
int n=strlen(T),m=strlen(s),i,j,k;
for(j=;j<n&&j<m&&T[j]==s[j];j++);
extend[]=j;
k=;
for(i=;i<n;i++)
{
int len=k+extend[k],L=Next[i-k];
if(L<len-i)extend[i]=L;
else
{
for(j=max(,len-i);j<m&&i+j<n&&s[j]==T[i+j];j++);
extend[i]=j;
k=i;
}
}
} int main()
{
scanf("%s",s1);
scanf("%s",t);
int lens=strlen(s1); reverse(s1,s1+lens);
for(int i=;i<lens;i++)s2[i]=s1[i];
s2[lens]='\0'; get_next(t);
ex_kmp(s2,t);
long long ans=;
P.solve();
for(int i=;i<lens;i++)
{
ans+=1ll*extend[i]*res[i-];
}
printf("%lld\n",ans);
return ;
}

...

回文自动机pam的更多相关文章

  1. 回文树(回文自动机PAM)小结

    回文树学习博客:lwfcgz    poursoul 边写边更新,大概会把回文树总结在一个博客里吧... 回文树的功能 假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀0~ ...

  2. 回文树/回文自动机(PAM)学习笔记

    回文树(也就是回文自动机)实际上是奇偶两棵树,每一个节点代表一个本质不同的回文子串(一棵树上的串长度全部是奇数,另一棵全部是偶数),原串中每一个本质不同的回文子串都在树上出现一次且仅一次. 一个节点的 ...

  3. 回文自动机(PAM) 入门讲解

    处理回文串,Manacher算法也是很不错,但在有些问题的处理上比较麻烦,比如求本质不同的子串的数量还需要结合后缀数组才能解决.今天的们介绍一种能够方便的解决关于回文串的问题的算法--PAM. 一些功 ...

  4. 洛谷P5496 回文自动机【PAM】模板

    回文自动机模板 1.一个串的本质不同的回文串数量是\(O(n)\)级别的 2.回文自动机的状态数不超过串长,且状态数等于本质不同的回文串数量,除了奇偶两个根节点 3.如何统计所有回文串的数量,类似后缀 ...

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

    题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(tra ...

  6. 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)

    模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...

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

    回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i ...

  8. 省选算法学习-回文自动机 && 回文树

    前置知识 首先你得会manacher,并理解manacher为什么是对的(不用理解为什么它是$O(n)$,这个大概记住就好了,不过理解了更方便做$PAM$的题) 什么是回文自动机? 回文自动机(Pal ...

  9. 洛谷P4287 [SHOI2011]双倍回文(回文自动机)

    传送门 听说有大佬用manacher$O(n)$过此题……太强啦…… 说一下PAM的做法吧.(看了题解之后发现)蛮简单的 我们肯定要先建出回文自动机的 然后如果是枚举每一个节点暴跳fail指针肯定得T ...

随机推荐

  1. vm虚拟机安装linux centos教程

    1 下载64btnhttp://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1810.iso 2 vm注意选择cen ...

  2. Centos 7.X 安装及常规设置

    一.制作USBHDD+启动 需要工具: UltraISO(软碟通) U盘 centos7镜像: http://www.centos.org 二.安装(有坑) U盘启动电脑,进入安装界面: 选中第一项, ...

  3. 美团店铺数据抓取 token解析与生成

    美团.点评网的token都是用一套加密算法,实际上就是个gzip压缩算法.加密了2次,第一次是加密了个sign值,然后把sign值带进去参数中进行第二次加密,最后得出token 分析请求 打开上海美食 ...

  4. 一张图讲解最少机器搭建FastDFS高可用分布式集群安装说明

     很幸运参与零售云快消平台的公有云搭建及孵化项目.零售云快消平台源于零售云家电3C平台私有项目,是与公司业务强耦合的.为了适用于全场景全品类平台,集团要求项目平台化,我们抢先并承担了此任务.并由我来主 ...

  5. ASP.NET Core 1.0: API的输入参数

    Web API是需要接受参数的,譬如,通常用于创建数据的POST method需要接受输入数据,而用于GET method也需要接受一些可选参数,譬如:为了性能起见,控制返回数据的数量是至关重要的. ...

  6. Python3.7.1学习(五) 将列表中的元素转化为数字并排序

    # 本文实例讲述了Python中列表元素转为数字的方法.分享给大家供大家参考,具体如下: # 有一个数字字符的列表: numbers = ['2', '4', '1', '3']print(numbe ...

  7. MySQL数据库root账户密码忘记两种处理方法(保有效)

    方法1: 1.停止MySQL服务 # kill `cat /var/run/mysqld/mysqld.pid` 或者 # pkill mysqld 2.创建一个密码赋值语句的文本文件 # vi my ...

  8. linux与Windows进程控制

    进程管理控制 这里实现的是一个自定义timer用于统计子进程运行的时间.使用方式主要是 timer [-t seconds] command arguments 例如要统计ls的运行时间可以直接输入t ...

  9. 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...

  10. python day 1 homework 2

    多级菜单 1 三级菜单 2 可依次选择进入各子菜单 3 所需新知识点,列表,字典 province_info = {":{"name":"黑龙江", ...