两道差不多的题,都是回文自动机right集合处理相关。

Victor and String

Victor loves to play with string. He thinks a string is charming as the string is a palindromic string.

Victor wants to play n times. Each time he will do one of following four operations.

  1. add a char c to the beginning of the string.

  2. add a char c to the end of the string.

  3. ask the number of different charming substrings.

  4. ask the number of charming substrings, the same substrings which starts in different location has to be counted.

At the beginning, Victor has an empty string.

1≤n≤100000

题解

来自翁文涛《回文树及其应用》。

CO int N=200000+10;

namespace PAM{
int str[N],L,R;
int tot,last[2];
int ch[N][26],fa[N],len[N],dep[N];
LL ans; IN int new_node(int l){
fill(ch[tot],ch[tot]+26,0);
len[tot]=l,dep[tot]=0;
return tot++;
}
IN void init(int n){
memset(str,-1,sizeof str),L=n,R=n-1;
tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
last[0]=last[1]=1;
ans=0;
}
int get_fail(int x,bool d){
if(d)while(str[R-len[x]-1]!=str[R]) x=fa[x];
else while(str[L+len[x]+1]!=str[L]) x=fa[x];
return x;
}
void extend(int c,bool d){
if(d) str[++R]=c;
else str[--L]=c;
int p=get_fail(last[d],d);
if(!ch[p][c]){
int cur=new_node(len[p]+2);
fa[cur]=ch[get_fail(fa[p],d)][c];
ch[p][c]=cur;
dep[cur]=dep[fa[cur]]+1;
}
last[d]=ch[p][c];
if(len[last[d]]==R-L+1) last[d^1]=last[d];
ans+=dep[last[d]];
}
} void real_main(int n){
PAM::init(n);
while(n--){
int opt=read<int>();
if(opt<=2){
char c[2];scanf("%s",c);
PAM::extend(c[0]-'a',opt-1);
}
else if(opt==3) printf("%d\n",PAM::tot-2);
else if(opt==4) printf("%lld\n",PAM::ans);
}
}
int main(){
for(int n;~scanf("%d",&n);) real_main(n);
return 0;
}

我发现初始化的时候必须memset。这是因为跳fail的时候可能会越界。

然后我加了一些特判,可以去掉memset

namespace PAM{
int str[N],L,R;
int tot,last[2];
int ch[N][26],fa[N],len[N],dep[N];
LL ans; IN int new_node(int l){
fill(ch[tot],ch[tot]+26,0);
len[tot]=l,dep[tot]=0;
return tot++;
}
IN void init(int n){
L=n,R=n-1;
tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
last[0]=last[1]=1;
ans=0;
}
int get_fail(int x,bool d){
if(d)while(assert(L<=R-len[x]-1 and R-len[x]-1<=R),str[R-len[x]-1]!=str[R]) x=fa[x];
else while(assert(L<=L+len[x]+1 and L+len[x]+1<=R),str[L+len[x]+1]!=str[L]) x=fa[x];
return x;
}
void extend(int c,bool d){
if(d) str[++R]=c;
else str[--L]=c;
int p=get_fail(len[last[d]]==R-L?fa[last[d]]:last[d],d); // edit
if(!ch[p][c]){
int cur=new_node(len[p]+2);
fa[cur]=ch[get_fail(fa[p],d)][c];
ch[p][c]=cur;
dep[cur]=dep[fa[cur]]+1;
}
last[d]=ch[p][c];
if(len[last[d]]==R-L+1) last[d^1]=last[d];
ans+=dep[last[d]];
}
}

APIO2014 回文串

考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。

数据满足1≤字符串长度≤300000。

题解

co int N=300000+10;
int last=1,tot=1;
int ch[N][26],fa[N]={1,1},len[N]={0,-1},siz[N];
char s[N]; int get_fa(int x,int i){
while(s[i-len[x]-1]!=s[i]) x=fa[x];
return x;
}
void extend(int i){
int p=get_fa(last,i);
int x=ch[p][s[i]-'a'];
if(!x){
x=++tot;
fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
len[x]=len[p]+2;
ch[p][s[i]-'a']=x;
}
++siz[x];
last=x;
}
int main(){
scanf("%s",s+1);int n=strlen(s+1);
for(int i=1;i<=n;++i) extend(i);
for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
LL ans=0;
for(int i=1;i<=tot;++i) ans=max(ans,(LL)siz[i]*len[i]);
printf("%lld\n",ans);
return 0;
}

后缀自动机做法

http://hzwer.com/6847.html

https://blog.csdn.net/u012288458/article/details/51785834

每找到一个回文串,就在所有的串中查找出现了多少次

因为暴力跳非常的慢,所以用倍增优化

每次查询都是从末尾节点开始,倍增找到最后一个长度大于等于p的节点

manacher算法证明了本质不同的回文串只有\(O(n)\)个,复杂度\(O(n\log n)\)

第一次写直接做的manacher算法,分析了一会儿。求偶回文串的时候以左端点代替空隙,然后其他操作基本一致。

co int N=6e5;
// Suffix Automaton
int last=1,tot=1;
int ch[N][26],fa[N],len[N],siz[N],pos[N]; // pos:out->in
void extend(int c,int po){
int p=last,cur=last=++tot;
len[cur]=len[p]+1,siz[cur]=1,pos[po]=cur;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++tot;
memcpy(ch[clone],ch[q],sizeof ch[q]);
fa[clone]=fa[q],len[clone]=len[p]+1;
fa[cur]=fa[q]=clone;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
int cnt[N],id[N],anc[N][21];
ll ans;
void query(int l,int r){
int p=pos[r];
for(int i=20;i>=0;--i)
if(len[anc[p][i]]>=r-l+1) p=anc[p][i];
ans=max(ans,(ll)siz[p]*(r-l+1));
} char s[N];
int n,p[N];
int main(){
scanf("%s",s+1),n=strlen(s+1);
for(int i=1;i<=n;++i) extend(s[i]-'a',i);
// build
for(int i=1;i<=tot;++i) ++cnt[len[i]];
for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
for(int i=1;i<=tot;++i) id[cnt[len[i]]--]=i;
for(int i=tot;i;--i){
int p=id[i];
siz[fa[p]]+=siz[p];
}
for(int i=1;i<=tot;++i){
int p=id[i];
anc[p][0]=fa[p];
for(int j=1;j<=20;++j) anc[p][j]=anc[anc[p][j-1]][j-1];
}
// Manacher
s[0]='@',s[n+1]='#';
int mx=0,id=1;
for(int i=1;i<n;++i){ // even, represent with left vertice
if(mx>i) p[i]=min(mx-i,p[2*id-i]);
else p[i]=0;
while(s[i+p[i]+1]==s[i-p[i]])
++p[i],query(i-p[i]+1,i+p[i]);
if(p[i]+i>mx) mx=p[i]+i,id=i;
}
mx=0,id=1;
for(int i=1;i<=n;++i){ // odd
if(mx>i) p[i]=min(mx-i,p[2*id-i]);
else p[i]=1,query(i-p[i]+1,i+p[i]-1);
while(s[i+p[i]]==s[i-p[i]])
++p[i],query(i-p[i]+1,i+p[i]-1);
if(p[i]+i>mx) mx=p[i]+i,id=i;
}
printf("%lld\n",ans);
return 0;
}

HDU5421 Victor and String 和 APIO2014 回文串的更多相关文章

  1. 3676: [Apio2014]回文串

    3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1740 Solved: 744 [Submit][Status ...

  2. 3676: [Apio2014]回文串 求回文串长度与出现次数的最大值

    「BZOJ3676」[Apio2014] 回文串   Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ...

  3. BZOJ 3676: [Apio2014]回文串

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2013  Solved: 863[Submit][Status ...

  4. bzoj 3676: [Apio2014]回文串 回文自动机

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status] ...

  5. [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  6. 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2343  Solved: 1031 Description 考 ...

  7. [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3097  Solved: 1408[Submit][Statu ...

  8. [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3396  Solved: 1568[Submit][Statu ...

  9. 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习

    写题遇上一棘手的题,[Apio2014]回文串,一眼看过后缀数组+Manacher.然后就码码码...过是过了,然后看一下[Status],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ...

随机推荐

  1. scala 正则

    package com.program import scala.util.matching.Regex object RegexTest { def main(args: Array[String] ...

  2. Maven设置MAVEN_OPTS环境变量

    原文地址:https://blog.csdn.net/porsche_gt3rs/article/details/78787491 一 原因: 运行mvn命令实际是执行java命令,既然是运行java ...

  3. Springboot Actuator之五:Springboot中的HealthAggregator、新增自定义Status

    springboot的actuator内置了/health的endpoint,很方便地规范了每个服务的健康状况的api,而且HealthIndicator可以自己去扩展,增加相关依赖服务的健康状态,非 ...

  4. 离线方式快速安装python模块以及相关依赖模块

    一般公司的服务器都是和外网隔离的,这个如果没有内部pip源的话,想要安装python的模块就需要去python官网一个一个下载依赖模块的包,然后逐个安装,这样做非常耗时间. 我们今天用的办法就是现在我 ...

  5. vim中常用折叠命令

    最常用3个折叠命令 .反复打开关闭折叠:za (意思就是,当光标处折叠处于打开状态,za关闭之,当光标处折叠关闭状态,打开之) .打开全部折叠:zR .关闭全部折叠:zM 小试折叠: :set fdm ...

  6. Maven:repositories、distributionManagement、pluginRepositories中repository的区别

    本文链接:https://blog.csdn.net/netyeaxi/article/details/95804076 目录 一.repositories中的repository 二.distrib ...

  7. Java+Python+前端 学习资料大全 百度云盘

    Java架构师3大阶段 链接:https://pan.baidu.com/s/1DlXh33y5t4cZUmZH0cLvCw 提取码:5s76 2019前端架构阶段 链接:https://pan.ba ...

  8. C#读写调整设置UVC摄像头画面-亮度

    有时,我们需要在C#代码中对摄像头的亮度进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ...

  9. Echarts X轴多项百分比的展示

    app.title = '堆叠柱状图'; option = { tooltip : { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type ...

  10. 使用Supervisord软件管理go服务进程

    一.介绍Supervisord软件1.什么是Supervisord?Supervisord是一个非常优秀的进程管理工具,使用Python开发.它可以在类UNIX系统的方式让用户来准确地监视和控制后台一 ...