• 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;
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-09-14
  • 2021-12-08
  • 2022-01-10
  • 2022-12-23
  • 2022-12-23
  • 2021-11-22
猜你喜欢
  • 2021-12-15
  • 2022-01-19
  • 2021-09-28
  • 2021-11-12
  • 2022-02-08
  • 2022-12-23
  • 2022-01-14
相关资源
相似解决方案