两道差不多的题,都是回文自动机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. java 查找指定包下的类

    package com.jason.test; import java.io.File; import java.io.IOException; import java.io.UnsupportedE ...

  2. Ognl 语法基础教程

    本文将力求用最简单的语言和实例,介绍一下 OGNL 的语法规则,文章主要内容参考自官方文档http://commons.apache.org/proper/commons-ognl/language- ...

  3. 将Javabean转化JSONObject为对象

    JSONObject.parseObject(JSONObject.toJSON(obj).toString()):

  4. CMD使用的几个小技巧

    一.自定义窗口初始化大小 以前在Windows 7的时候感觉打开cmd时窗口初始化的大小还是比较合适的,但到Windows 10之后打开cmd窗口就很大一点都不适应----当然也可能是新电脑分辨率比较 ...

  5. JavaSE 面试题: 方法的参数传递机制

    JavaSE 面试题 方法的参数传递机制 import java.util.Arrays; public class Test { public static void main(String[] a ...

  6. 备忘录(Memento)模式

    备忘录模式又叫做快照模式或者Token模式. 备忘录对象是一个用来存储另一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来 ...

  7. C++之救济金发放问题

    n(n<20)个人站成一圈,逆时针编号为1~n.有两个官员,A从1开始逆时针数,B从n开始顺时针数.在每一轮中,官员A数k个就停下来,官员B数m个就停下来(注意有可能两个官员停在同一个人上).接 ...

  8. 如何选择CPU

    一.品牌: 选择哪家公司的处理器,AMD公司和inter公司的处理器相比较,AMD在三维制作.游戏应用.和视频处理方面突出,inter的处理器在商业应用.多媒体应用.平面设计方面有优势,性能方面,同档 ...

  9. BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并

    传送门--BZOJCH 考虑两种情况: 1.答案由一个最长公共子串+可能的一个模糊匹配位置组成.这个用SAM求一下最长公共子串,但是需要注意只出现在\(S\)的开头和\(T\)的结尾的子串是不能够通过 ...

  10. 获取Excel

    默认Excel文档为 代码如下   需要下载  "EPPlus.Core" var file = Directory.GetCurrentDirectory() + "\ ...