回文自动机模板

标准版

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int N=26;
struct Palindromic_Tree
{
    int next[maxn][N];
    int fail[maxn];
    int cnt[maxn];//第i个节点表示的回文串出现的次数,最后要调用count函数完成计算
    int num[maxn];//以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
    int len[maxn];//节点i表示的回文串的长度
    int S[maxn];//存放添加的字符
    int last;
    int n;//字符数组指针
    int p;//节点指针
    int newnode(int l)
    {
        memset(next[p],0,sizeof next[p]);
        cnt[p]=0;
        num[p]=0;
        len[p]=l;
        return p++;
    }
    void init()
    {
        p=0;
        newnode(0);
        newnode(-1);
        last=0;
        n=0;
        S[n]=-1;
        fail[0]=1;
    }
    int get_fail(int x)
    {
        while(S[n-len[x]-1]!=S[n])
            x=fail[x];
        return x;
    }
    void add(int c)
    {
        c-='0';
        S[++n]=c;
        int cur=get_fail(last);
        if(!next[cur][c])//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
        {
            int now=newnode(len[cur]+2);
            fail[now]=next[get_fail(fail[cur])][c];
            next[cur][c]=now;
            num[now]=num[fail[now]]+1;
        }
        last=next[cur][c];
        cnt[last]++;
    }
    void count()
    {
        for(int i=p-1;i>=0;i--)
            cnt[fail[i]]+=cnt[i];
    }
}pam;
char s[maxn];
int main()
{
    pam.init();
    scanf("%s",s);
    int n=strlen(s);
    for(int i=0;i<n;i++)
    {
        pam.add(s[i]);
    }
}

双向插入版

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int N=26;
struct Palindromic_Tree {
    static const int maxn=400000;
    static const int Letter=26;
    deque<int> text;
    int len[maxn];//len[i]表示节点i表示的回文串的长度
    int cnt[maxn];//第 i 节点表示的回文串出现的次数、注意最后调用 getCnt 函数完成计算
    int num[maxn];//表示以节点 i 代表的回文串端点为端点的不同回文串个数
    int next[maxn][Letter];//next静态指针和字典树类似,指向的串为当前串两端加上同一个字符构成
    int fail[maxn];//失配指针
    int odd, even;//奇偶原始节点
    int pre, suf;
    int totNode;//自动机所有节点的个数
    LL totNum;//串中所有回文串数量
    int newNode(int _len)
    {
        int ret=totNode++;
        len[ret]=_len;
        cnt[ret]=num[ret]=0;
        fail[ret]=0;
        memset(next[ret],0,sizeof(next[ret]));
        return ret;
    }
    inline void init()
    {
        text.clear();
        totNode=0;
        totNum=0;
        even=newNode(0);
        odd=newNode(-1);
        fail[even]=fail[odd]=odd;
        pre=suf=even;
    }
    int encode(char c)
    {
        return c - 'a';
    }
    template<typename FunT>
    int getFail(int ch,int cur,FunT getNext)
    {
        for(int i=getNext(len[cur]);
            i<0||i>=(int)text.size()||text[i]!=ch;
            cur=fail[cur],i=getNext(len[cur]));
        return cur;
    }
    template<typename FunT>
    int Insert(int ch,int last,FunT getNext)
    {
        last=getFail(ch,last,getNext);
        if(!next[last][ch])
        {
            int cur=newNode(len[last]+2);
            fail[cur]=next[getFail(ch,fail[last],getNext)][ch];
            next[last][ch]=cur;
            num[cur]=num[fail[cur]]+1;
        }

        last=next[last][ch];
        totNum+=(LL)num[last];
        cnt[last]++;
        return last;
    }
    int push_front(char c)
    {
        text.push_front(encode(c));
        pre=Insert(encode(c),pre,[](int i)->int{ return i+1;});
        if(len[pre]==(int)text.size()) suf=pre;
        return totNode;
    }
    int push_back(char c)
    {
        text.push_back(encode(c));
        suf=Insert(encode(c),suf,[this](int i)->int{ return this->text.size()-i-2; });
        if(len[suf]==(int)text.size()) pre=suf;
        return totNode;
    }

    int push_front(char *s)
    {
        int ret=0;
        for(int i=0;s[i];i++)
            ret=push_front(s[i]);
        return ret;
    }

    int push_back(char *s)
    {
        int ret=0;
        for(int i=0;s[i];i++)
            ret=push_back(s[i]);
        return ret;
    }

    inline void getCnt()
    {
        for(int i=totNode-1;i>=0;i--)
            cnt[fail[i]]+=cnt[i];
    }

}pam;

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值