回文树/回文自动机(PAM)学习笔记
回文树(也就是回文自动机)实际上是奇偶两棵树,每一个节点代表一个本质不同的回文子串(一棵树上的串长度全部是奇数,另一棵全部是偶数),原串中每一个本质不同的回文子串都在树上出现一次且仅一次。
一个节点的fail指针指向它的最长回文后缀(不包括自身,所有空fail均连向1)。归纳容易证明,当在原串末尾新增一个字符时,回文树上至多会新增一个节点,这也证明了一个串本质不同的回文子串个数不会超过n。
建树时采用增量构造法,当考虑新字符s[i]时,先找到以s[i-1]为结尾的节点p,并不断跳fail。若代表新增回文子串的节点已存在则直接结束,否则通过fail[p]不断跳fail找到新节点的fail。
0,1号节点均不代表串,常数大于manacher。初始化fail[0]=fail[1]=1,len[1]=-1,tot=1,last=0。
[BZOJ2160]拉拉队排练
建立后缀树后树上DP求出每种回文子串的出现次数即可。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=,mod=;
char s[N];
ll K,sm;
int n,ans=,lst,nd=,len[N],fail[N],son[N][],sz[N];
struct P{ int l,c; }c[N];
bool operator <(const P &a,const P &b){ return a.l>b.l; } int ksm(int a,int b){
int s=;
for (; b; a=1ll*a*a%mod,b>>=)
if (b & ) s=1ll*s*a%mod;
return s;
} void ext(int c,int n,char s[]){
int p=lst;
while (s[n-len[p]-]!=s[n]) p=fail[p];
if (!son[p][c]){
int np=++nd,q=fail[p];
while (s[n-len[q]-]!=s[n]) q=fail[q];
len[np]=len[p]+; fail[np]=son[q][c]; son[p][c]=np;
}
lst=son[p][c]; sz[lst]++;
} int main(){
freopen("bzoj2160.in","r",stdin);
freopen("bzoj2160.out","w",stdout);
scanf("%d%lld%s",&n,&K,s+);
len[]=-; fail[]=fail[]=;
rep(i,,n) ext(s[i]-'a',i,s);
for (int i=nd; i; i--) sz[fail[i]]+=sz[i];
rep(i,,nd) c[i-]=(P){len[i],sz[i]};
sort(c+,c+nd);
rep(i,,nd-){
if (!(c[i].l&)) continue;
ll t=min(K,(ll)c[i].c); ans=1ll*ans*ksm(c[i].l,t)%mod; K-=t;
if (!K) break;
}
printf("%d\n",K?-:ans);
return ;
}
BZOJ2160
[BZOJ3676][APIO2014]回文串
显然建出回文树后求出每个点的出现次数与长度即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
char s[N];
ll ans;
int n,lst,nd=,len[N],fail[N],sz[N],son[N][]; void ext(int c,int n,char s[]){
int p=lst;
while (s[n-len[p]-]!=s[n]) p=fail[p];
if (!son[p][c]){
int np=++nd,q=fail[p];
while (s[n-len[q]-]!=s[n]) q=fail[q];
len[np]=len[p]+; fail[np]=son[q][c]; son[p][c]=np;
}
sz[lst=son[p][c]]++;
} int main(){
freopen("bzoj3676.in","r",stdin);
freopen("bzoj3676.out","w",stdout);
scanf("%s",s+); n=strlen(s+);
fail[]=fail[]=; len[]=-; s[]=-;
rep(i,,n) ext(s[i]-'a',i,s);
for (int i=nd; i; i--) sz[fail[i]]+=sz[i];
rep(i,,nd) ans=max(ans,1ll*sz[i]*len[i]);
printf("%lld\n",ans);
return ;
}
BZOJ3676
[CF17E]Palisection
正难则反,所有回文串对数减去不相交对数。以某个位置结尾的回文子串个数等于它在回文树上代表的节点的深度,后缀和优化一下即可。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
typedef long long ll;
using namespace std; const int N=,mod=;
char s[N];
int n,cnt,ans,nd,lst,p1[N],p2[N],dep[N],to[N],nxt[N],val[N],h[N],fail[N],len[N]; void add(int u,int v,int w){ to[++cnt]=v; nxt[cnt]=h[u]; val[cnt]=w; h[u]=cnt; } void init(){
rep(i,,nd) h[i]=fail[i]=len[i]=dep[i]=;
cnt=lst=; nd=; len[]=-; fail[]=fail[]=;
} int son(int x,int c){ For(i,x) if (val[i]==c) return k=to[i]; return ; } void ext(int c,int n,char s[]){
int p=lst;
while (s[n-len[p]-]!=s[n]) p=fail[p];
if (!son(p,c)){
int np=++nd,q=fail[p];
while (s[n-len[q]-]!=s[n]) q=fail[q];
len[np]=len[p]+; fail[np]=son(q,c); dep[np]=dep[fail[np]]+; add(p,np,c);
}
lst=son(p,c);
} int main(){
freopen("cf17e.in","r",stdin);
freopen("cf17e.out","w",stdout);
scanf("%d%s",&n,s+); init();
rep(i,,n) ext(s[i]-'a',i,s),p1[i]=dep[lst],ans=(ans+p1[i])%mod;
ans=1ll*ans*(ans-)/%mod; reverse(s+,s+n+); init();
rep(i,,n) ext(s[i]-'a',i,s),p2[n-i+]=dep[lst];
for (int i=n; i; i--) p2[i]=(p2[i]+p2[i+])%mod;
rep(i,,n) ans=(ans-1ll*p1[i]*p2[i+]%mod+mod)%mod;
printf("%d\n",ans);
return ;
}
CF17E
[Aizu2292]Common Palindromes
给定S,T,询问有多少(l1,r1,l2,r2)使得S[l1,r1]回文且S[l1,r1]=T[l2,r2]。
显然对S建出回文自动机然后T在上面跑,记录每个S中回文串的出现次数以及T中有多少个子串与此串匹配。注意初始x=1(可以认为回文树的根是1),且匹配是不仅要看此节点是否有对应子节点,也要看s[i-len[x]-1]是否等于s[i]。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
char s[N];
ll ans;
int n,lst,nd=,f[N],son[N][],fail[N],len[N],sz[N]; void ext(int c,int n,char s[]){
int p=lst;
while (s[n-len[p]-]!=s[n]) p=fail[p];
if (!son[p][c]){
int np=++nd,q=fail[p];
while (s[n-len[q]-]!=s[n]) q=fail[q];
len[np]=len[p]+; fail[np]=son[q][c]; son[p][c]=np;
}
sz[lst=son[p][c]]++;
} int main(){
freopen("Aizu2292.in","r",stdin);
freopen("Aizu2292.out","w",stdout);
len[]=-; fail[]=fail[]=;
scanf("%s",s+); n=strlen(s+);
rep(i,,n) ext(s[i]-'A',i,s);
scanf("%s",s+); n=strlen(s+); int x=;
rep(i,,n){
int c=s[i]-'A';
while (x!= && (!son[x][c] || s[i]!=s[i-len[x]-])) x=fail[x];
if (son[x][c] && s[i]==s[i-len[x]-]) x=son[x][c],f[x]++;
}
for (int i=nd; i; i--) f[fail[i]]+=f[i],sz[fail[i]]+=sz[i];
rep(i,,nd) ans+=1ll*f[i]*sz[i];
printf("%lld\n",ans);
return ;
}
Aizu2292
[BZOJ2342][SHOI2011]双倍回文
就是求后半段也为回文串的回文串个数,在fail树上DFS并维护每个长度的回文串个数即可。
或者考虑求half[i]表示节点i的最深祖先满足len[half[i]]<=len[i]/2,这个同样可以在建树的时候求得。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
char s[N];
int n,ans,lst,nd=,fail[N],son[N][],len[N],half[N]; void ext(int c,int n,char s[]){
int p=lst;
while (s[n-len[p]-]!=s[n]) p=fail[p];
if (!son[p][c]){
int np=++nd,q=fail[p];
while (s[n-len[q]-]!=s[n]) q=fail[q];
len[np]=len[p]+; fail[np]=son[q][c]; son[p][c]=np;
if (len[np]==) half[np]=;
else{
int pos=half[p];
while (s[n-len[pos]-]!=s[n] || (len[pos]+)*>len[np]) pos=fail[pos];
half[np]=son[pos][c];
}
}
lst=son[p][c];
} int main(){
freopen("bzoj2342.in","r",stdin);
freopen("bzoj2342.out","w",stdout);
scanf("%d%s",&n,s+); len[]=-; fail[]=fail[]=;
rep(i,,n) ext(s[i]-'a',i,s);
rep(i,,nd) if (len[half[i]]*==len[i] && len[i]%==) ans=max(ans,len[i]);
printf("%d\n",ans);
return ;
}
BZOJ2342
回文树/回文自动机(PAM)学习笔记的更多相关文章
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...
- 回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities
Palindromes and Super Abilities Problem's Link: http://acm.timus.ru/problem.aspx?space=1&num=19 ...
- 回文树(回文自动机PAM)小结
回文树学习博客:lwfcgz poursoul 边写边更新,大概会把回文树总结在一个博客里吧... 回文树的功能 假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀0~ ...
- 回文树(回文自动机) - BZOJ 3676 回文串
BZOJ 3676 回文串 Problem's Link: http://www.lydsy.com/JudgeOnline/problem.php?id=3676 Mean: 略 analyse: ...
- BZOJ 3676: [Apio2014]回文串 回文树 回文自动机
http://www.lydsy.com/JudgeOnline/problem.php?id=3676 另一种更简单更快常数更小的写法,很神奇……背板子. #include<iostream& ...
- JavaScript权威设计--JavaScript脚本化文档Document与CSS(简要学习笔记十五)
1.Document与Element和TEXT是Node的子类. Document:树形的根部节点 Element:HTML元素的节点 TEXT:文本节点 >>HtmlElement与 ...
- PAM学习笔记
想了想 还是要先把字符串的东西先都学完告一段落了再说 时间不多了 加油~. PAM 回文自动机 比SAM简单到不知道哪里去了. 回文自动机和其他自动机一样有字符集 有状态 有转移. 一个字符串的回文自 ...
- 「AC自动机」学习笔记
AC自动机(Aho-Corasick Automaton),虽然不能够帮你自动AC,但是真的还是非常神奇的一个数据结构.AC自动机用来处理多模式串匹配问题,可以看做是KMP(单模式串匹配问题)的升级版 ...
- 设备树(device tree)学习笔记
作者信息 作者:彭东林 邮箱:pengdonglin137@163.com 1.反编译设备树 在设备树学习的时候,如果可以看到最终生成的设备树的内容,对于我们学习设备树以及分析问题有很大帮助.这里我们 ...
随机推荐
- 下载 python
https://www.python.org/ftp/python/ https://www.cnblogs.com/linxue/p/10097785.html https://blog.csdn. ...
- shell 小数比较大小
a=1.6b=6.1c=`echo "$a > $b" | bc`然後,如果 $c 是 1 ,那就成立,否則不成立. 参考: http://ju.outofmemory.cn ...
- Internet地址结构
IP地址结构及分类寻址 IP地址 = <网络号> + <主机号> ------------IPv4(32bit)点分四组表示法: 192.168.31.1 ...
- Mongoose 多表(N个表)关联查询aggregate
Mongoose 多表(N个表)关联查询概述 需求:文章(article),文章分类(articlecate),用户(user)这三个表之间的关系,一篇文章对应文章分类表中的某个类型,对应着用户表中的 ...
- 东芝300D粉盒清零
东芝300D粉盒清零 1:打开前盖 2:按"OK"键3秒,等 显示 "更换硒鼓"(注:不用选 是/否,直接进入第3步) 3:按"启用"键 4 ...
- Vue/小程序/小程序云+Node+Mongo开发微信授权、支付和分享
大家好,我是河畔一角,今天给大家介绍我的第三门实战课程:基于微信开发的H5.小程序和小程序云的授权.支付和分享专项课程. 一.这一次为什么会选择微信支付和分享的课题呢? 金庸的小说中曾提到:有人的地方 ...
- nginx 日志打印响应时间 request_time 和 upstream_response_time
设置log_format,添加request_time,$upstream_response_time,位置随意 og_format main '"$request_time" ...
- [oracle/java/sql]用于上十万批量数据插入Oracle表的Java程序
程序下载:https://files.cnblogs.com/files/xiandedanteng/LeftInnerNotExist20191222.rar 原理:Oracle的Insert al ...
- Java: Java终止线程的几种方式
首先说明,使用stop方法终止的方式已经在很久之前就被废弃了,在加锁的情况下有可能会造成死锁,这里不做讨论. 1. 使用标志位终止线程 在run()方法执行完毕后,该线程就终止了.但是在某些特殊的情况 ...
- setDefaultDllDirectories无法定位动态链接库kernel32.dll
参考链接 : https://blog.csdn.net/gdali/article/details/93084828 https://tieba.baidu.com/p/5795675519?red ...