HDU5421 Victor and String 和 APIO2014 回文串
两道差不多的题,都是回文自动机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.
add a char c to the beginning of the string.
add a char c to the end of the string.
ask the number of different charming substrings.
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 回文串的更多相关文章
- 3676: [Apio2014]回文串
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1740 Solved: 744 [Submit][Status ...
- 3676: [Apio2014]回文串 求回文串长度与出现次数的最大值
「BZOJ3676」[Apio2014] 回文串 Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ...
- BZOJ 3676: [Apio2014]回文串
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2013 Solved: 863[Submit][Status ...
- bzoj 3676: [Apio2014]回文串 回文自动机
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 844 Solved: 331[Submit][Status] ...
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...
- 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2343 Solved: 1031 Description 考 ...
- [BZOJ3676][APIO2014]回文串(Manacher+SAM)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3097 Solved: 1408[Submit][Statu ...
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3396 Solved: 1568[Submit][Statu ...
- 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习
写题遇上一棘手的题,[Apio2014]回文串,一眼看过后缀数组+Manacher.然后就码码码...过是过了,然后看一下[Status],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ...
随机推荐
- cad.arx 自定义实体之编译第一个项目(甜头)
本篇不从零开始讲如何制造自定义图元,而是教新手们如何设置了环境之后编译张帆书中的代码. 利用vs2010编译 张帆<AutoCAD ObjectARX(VC)开发基础与实例教程>一书中的自 ...
- scrapy中间件中发送邮件
背景介绍:之前写过通过通过scrapy的扩展发送邮件,在爬虫关闭的时候发送邮件.那个时候有个问题就是MailSender对象需要return出去.这次需要在中间件中发送邮件,但是中间件中不能随便使用r ...
- 模板方法(TemplateMethod)模式
模板方法模式是准备一个抽象类,将部分逻辑以具体方法以及构造子的形式出现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑部分有不同的实现.这也 ...
- c++11多线程记录0
两种并发编程模型 多进程 进程间通信常用的几种方式: 文件 管道 消息队列 多线程 一个进程中存在的多个线程,通常通过共享内存来通信,(说的非常非常粗俗,就是通过类似"全局变量"的 ...
- c语言错题本
()malloc(sizeof()) 在stdlib.h包中
- 【题解】Luogu P5319 [BJOI2019]奥术神杖
原题传送门 题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力 看着根号和累乘不爽,我们两边同 ...
- Android studio 混淆配置
混淆 studio 使用Proguard进行混淆,其是一个压缩.优化和混淆java字节码文件的一个工具. 功能:Shrinking(压缩).Optimization(优化).Obfuscattion( ...
- chrome安装插件
看了很多的解决办法,也试了很多种,有的有点用,有的只能用一次,最后成功了,在这里总结一下 一.首先下载 很多人下载的都ctx格式的,然后拖进去安装,用了一次就崩溃了,主要还是安装方式不对,一般需要将下 ...
- Git 多人协作 以及推送分支
参考链接:https://www.liaoxuefeng.com/wiki/896043488029600/900375748016320 当你从远程仓库克隆时,实际上Git自动把本地的仓库的mast ...
- Django--模型层进阶
目录 QuerySet对象 可切片 可迭代 惰性查询 缓存机制 何时查询集不会被缓存? exists()与iterator()方法 exists() iterator() 中介模型 查询优化 表数据 ...