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],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ...
随机推荐
- [环境部署] Linux搭建SVN服务器之Centos篇
使用 service iptables stop 关闭防火墙 安装步骤如下: 1.yum install subversion2.输入rpm -ql subversion查看安装位置,如下:rpm - ...
- osx或windows系统下,用ftp上传文件到阿里云虚拟主机脚本
某天突然发现,一直在用的ftp工具并不好用,操作界面太过繁琐,而且不太稳定.于是自己找资料,整合了几句虽然简单,但是方便的代码. mac脚本 #从本地向FTP批量上传文档 需要赋予该.shell文件权 ...
- C#调用摄像头(AForge)实现扫描条码解析(Zxing)功能
网上找了很多代码,都比较零散,以下代码纯自己手写,经过测试.下面有链接,下载后可以直接使用. 介绍: 自动识别:点击Start按钮会调用PC摄像头,代码内置Timer,会每100毫秒识别一下当前摄像头 ...
- Linux命令中service的用法
用途说明 service命令用于对系统服务进行管理,比如启动(start).停止(stop).重启(restart).查看状态(status)等.相关的命令还包括chkconfig.ntsysv等,c ...
- Linux下c语言TCP多线程聊天室
开发环境:Linux,GCC 相关知识:TCP(博客:传送门),线程 附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制),希望大佬赐教. 那么话不多说,放码过来: 码云:传送门, ...
- K8S学习笔记之k8s使用ceph实现动态持久化存储
0x00 概述 本文章介绍如何使用ceph为k8s提供动态申请pv的功能.ceph提供底层存储功能,cephfs方式支持k8s的pv的3种访问模式ReadWriteOnce,ReadOnlyMany ...
- sql server 根据字段去重
使用 row_number() over (partition by 要去重的字段 order by 排序字段) 数据库表结构 学生成绩表 UserGrade Id int ...
- The underlying connection was closed: An unexpected error occurred on a receive
解决方法 webRequest.KeepAlive = false; ServicePointManager.ServerCertificateValidationCallback += (s, ce ...
- PHP-FPM的相关知识的深度解释
一.需要搞清楚几个名词概念 1. CGI(Common Gateway Interface,CGI)通用网关接口, 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展 ...
- jQuery---jq基础了解(语法,特性),JQ和JS的区别对比,JQ和JS相互转换,Jquery的选择器(基础选择器,层级选择器,属性选择器),Jquery的筛选器(基本筛选器,表单筛选器),Jquery筛选方法
jQuery---jq基础了解(语法,特性),JQ和JS的区别对比,JQ和JS相互转换,Jquery的选择器(基础选择器,层级选择器,属性选择器),Jquery的筛选器(基本筛选器,表单筛选器),Jq ...