回文自动机pam
目的:类似回文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的更多相关文章
- 回文树(回文自动机PAM)小结
回文树学习博客:lwfcgz poursoul 边写边更新,大概会把回文树总结在一个博客里吧... 回文树的功能 假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀0~ ...
- 回文树/回文自动机(PAM)学习笔记
回文树(也就是回文自动机)实际上是奇偶两棵树,每一个节点代表一个本质不同的回文子串(一棵树上的串长度全部是奇数,另一棵全部是偶数),原串中每一个本质不同的回文子串都在树上出现一次且仅一次. 一个节点的 ...
- 回文自动机(PAM) 入门讲解
处理回文串,Manacher算法也是很不错,但在有些问题的处理上比较麻烦,比如求本质不同的子串的数量还需要结合后缀数组才能解决.今天的们介绍一种能够方便的解决关于回文串的问题的算法--PAM. 一些功 ...
- 洛谷P5496 回文自动机【PAM】模板
回文自动机模板 1.一个串的本质不同的回文串数量是\(O(n)\)级别的 2.回文自动机的状态数不超过串长,且状态数等于本质不同的回文串数量,除了奇偶两个根节点 3.如何统计所有回文串的数量,类似后缀 ...
- 【XSY2715】回文串 树链剖分 回文自动机
题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(tra ...
- 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)
模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...
- 【回文自动机】bzoj3676 [Apio2014]回文串
回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i ...
- 省选算法学习-回文自动机 && 回文树
前置知识 首先你得会manacher,并理解manacher为什么是对的(不用理解为什么它是$O(n)$,这个大概记住就好了,不过理解了更方便做$PAM$的题) 什么是回文自动机? 回文自动机(Pal ...
- 洛谷P4287 [SHOI2011]双倍回文(回文自动机)
传送门 听说有大佬用manacher$O(n)$过此题……太强啦…… 说一下PAM的做法吧.(看了题解之后发现)蛮简单的 我们肯定要先建出回文自动机的 然后如果是枚举每一个节点暴跳fail指针肯定得T ...
随机推荐
- python的基础认识
一.python的简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名 ...
- 微信APP支付【签名失败】
最近在做微信APP支付 遇到一个问题 请求预下单时,接口返回签名错误 由于之前没有成功的交互,刚开始检查程序的错误,经过多次修改,发现依然是签名错误,可能出现的问题如下: 1.该签名密钥不是AppSe ...
- java中hashmap容量的初始化
HashMap使用HashMap(int initialCapacity)对集合进行初始化. 在默认的情况下,HashMap的容量是16.但是如果用户通过构造函数指定了一个数字作为容量,那么Hash会 ...
- linux文件时间
Linux 查看文件修改时间(精确到秒)(简单) ls --full-time 查看文件时间戳命令:stat test.txt linux 下查看文件修改时间 等(详细) 查看文件时间戳命令:stat ...
- Hook原理--逆向开发
今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解.Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术.按照如下过程进行讲解 Hook概述 Hook技术方式 f ...
- 关于PHP中依赖注入的详细介绍
依赖注入原理: 依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式.简而言之就是可以让我们在类的方法中更加方便的调用与之关联的类. 实例讲解: 假设有一个这样 ...
- SQL查询优化实践
为什么要优化 系统的吞吐量瓶颈往往出现在数据库的访问速度上,即随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢,且数据是存放在磁盘上的,读写速度无法和内存相比 如何优化 设计数据库时 ...
- enable_shared_from_this用法分析
一.背景 在为什么需要异步编程文章末尾提到,"为了使socket和缓冲区(read或write)在整个异步操作的生命周期一直保持活动,我们需要采取特殊的保护措施.你的连接类需要继承自enab ...
- 创建指定python版本的虚拟环境
使用virtualenvwrapper管理虚拟环境 鉴于virtualenv不便于对虚拟环境集中管理,所以推荐直接使用virtualenvwrapper. virtualenvwrapper提供了一系 ...
- SpringBoot第一次案例
一.Spring Boot 入门 1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Spring技术栈的一个大整合: J2EE开发的一站式解决方案: 2.微服务 2014,m ...