- KMP,扩展KMP和Manacher就不写了,感觉没多大意思。
- 之前感觉后缀自动机简直可以解决一切,所以不怎么写后缀数组。
- 马拉车主要是通过对称中心解决问题,有的时候要通过回文串的边界解决问题,这个时候回文树就用到了,又好写,又强大。
- 之前整理过一篇后缀自动机的。感觉还要整理一下,顺便把回文树,后缀数组也整理一下
- 很久没写专题了,如果有空,把回文自动机也学习一下。
前置技能: 马拉车,KMP。 其实也没关系,就是对比一下。
马拉车是利用对称的思想,得到每个点或者空格为对称中心的最长回文。
KMP有失配指针,回文树也有,指向失配后最长的回文串。
前置理论: 一个字符串的本质不同的回文串最多有|S|个。所以,回文树的空间和时间是线性的。
保存信息:我们把每个回文串对应到一个节点里。
struct node{ int len,num,fail,son[26],dep; }t[maxn];
其中,len是回文串的长度;num是出现次数;son是儿子指针,用于匹配,看是否能增加长度;dep是指这个回文串失配次数,即以它的最后一个字符为尾的回文串个数; fail是失配指针;
功能:我们可以得到所有的回文串; 所有本质不同的回文串; 回文串的出现次数; 以某个位置结尾的回文串个数;
实现:首先,初始化两个节点1号和0号,分别表示奇数偶数长度的回文串。 他们都指向1号节点,而1号节点的长度设置尾-1,这样的话,确保每个位置结尾的回文串长度至少是-1+2=1;
void init() { tot=last=1; t[0].len=0; t[1].len=-1; t[0].fail=t[1].fail=1; }
完整代码:
struct PAT { struct node{ int len,num,fail,son[26]; }t[maxn]; int last,n,tot,s[maxn]; void init() { memset(t,0,sizeof(t)); tot=last=1; n=0; t[0].len=0; t[1].len=-1; t[0].fail=t[1].fail=1; s[0]=-1; } int add(int c){ int p=last; s[++n]=c; while(s[n]!=s[n-1-t[p].len]) p=t[p].fail; if(!t[p].son[c]){ int v=++tot,k=t[p].fail; while(s[n]!=s[n-t[k].len-1]) k=t[k].fail; t[v].fail=t[k].son[c]; t[v].len=t[p].len+2; t[v].num=t[t[v].fail].num+1; t[p].son[c]=v; } last=t[p].son[c]; return t[last].num; } }T;
例题一:HDU5658:CA Loves Palindromic
题意:给定字符串S,|S|<1000;Q次询问区间不用本质的回文串数量。
思路:以每个左端点建立回文树即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1010; char c[maxn]; int bb[maxn]; int N,Q,fcy[maxn][maxn]; struct PT { struct node{ int fail,len,son[26]; }t[maxn]; int tot,last; void init() { memset(t,0,sizeof(t)); t[0].fail=t[1].fail=1; t[1].len=-1; last=1; tot=1; bb[0]=-1; bb[1]=-2; } void add(int s,int n) { int p=last; bb[n]=s; while(bb[n-t[p].len-1]!=bb[n]) p=t[p].fail; if(!t[p].son[s]) { int v=++tot,k=t[p].fail; t[v].len=t[p].len+2; while(bb[n-t[k].len-1]!=bb[n]) k=t[k].fail; t[v].fail=t[k].son[s]; t[p].son[s]=v; } last=t[p].son[s]; } }T; void solve() { rep(i,1,N){ T.init(); rep(j,i,N) { T.add(c[j]-'a',j-i+1); fcy[i][j]=T.tot-1; } } scanf("%d",&Q); rep(i,1,Q){ int L,R; scanf("%d%d",&L,&R); printf("%d\n",fcy[L][R]); } } int main() { int T;scanf("%d",&T); while(T--){ memset(c,0,sizeof(c)); scanf("%s",c+1); N=strlen(c+1); solve(); } return 0; }