两道差不多的题,都是回文自动机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. python中进程、线程、协程简述

    进程 python中使用multiprocessing模块对进程进行操作管理 进程同步(锁.信号量.事件) 锁 —— multiprocessing.Lock 只要用到了锁 锁之间的代码就会变成同步的 ...

  2. Maven 教程(10)— Maven依赖详解

    原文地址:https://blog.csdn.net/liupeifeng3514/article/details/79545022 1.何为依赖? 比如你是个男的,你要生孩子,呸呸呸…男的怎么生孩子 ...

  3. Lab_1:练习4——分析bootloader加载ELF格式的OS的过程

    一.实验内容 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代码和通过qemu来运行并调试bootloader&OS, bootloader如何读取硬盘扇 ...

  4. eDiary

    多年过去,您经历了BBS.论坛.博客.推特.微博 ...,但在电脑的某个 角落,eDiary始终为你守护发自你内心的声音. eDiary的作用不仅仅在于写日记,您也可以用它来记流水帐.写工作日志, 记 ...

  5. Apache Kafka使用默认配置执行一些负载测试来完成性能测试和基准测试

    Kafka是一种分布式,分区,复制的提交日志服务.它提供了消息传递系统的功能.   我们先来看看它的消息传递术语: Kafka在称为主题的类别中维护消息的提要. 我们将调用向Kafka主题生成器发布消 ...

  6. Django 安装使用

    Django 安装使用 Django 介绍: Django是一个开放源代码的Web应用框架,由Python写成.采用了MVT的框架模式,即模型M,视图V和模版T.它最初是被开发来用于管理劳伦斯出版集团 ...

  7. Google Guava Cache 全解析

    Google guava工具类的介绍和使用https://blog.csdn.net/wwwdc1012/article/details/82228458 LoadingCache缓存使用(Loadi ...

  8. 3、Vue实例的属性

    1.获取Vue实例的属性 2.data属性 每个Vue实例都会代理其data对象里所有的属性.如果实例创建之后添加或者更改属性,他不会触发视图更新. 这句话说了下面两件事情 1.每个Vue实例都会代理 ...

  9. 修改dedecms 一些配置cfg_softname,cfg_soft_enname,cfg_soft_devteam

    1.找到include 中的common.inc.php 直接修改就可以了.

  10. 虚拟化x86的三种途径

    虚拟化x86的三种途径 作者:缪天翔链接:https://www.zhihu.com/question/20145026/answer/34527331 x86上的全系统虚拟化有三种主要的途径: 二进 ...