码迷,mamicode.com
首页 > 其他好文 > 详细

别人的回文自动机

时间:2019-08-03 21:43:35      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:print   out   last   return   int   tree   eps   include   count()   

#include<bits/stdc++.h>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define ALL(x) x.begin(),x.end()
#define pb push_back
//#define mp make_pair
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int maxn=3e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
using namespace std;
typedef double db;
const db eps=1e-10;
const db pi=acos(-1);
const int MAXN=300005;
const int N=26;
int ans[maxn],p[maxn*2];
char s[maxn];
void Manacher(char *s,int n,int *pa){
    pa[0] = 1;
    for(int i=1,j=0;i<(n<<1)-1;++i){
        int p = i >> 1 , q = i - p , r = ((j + 1)>>1) + pa[j] - 1;
        pa[i] = r < q ? 0 : min(r - q + 1 , pa[(j<<1) - i]);
        while(0 <= p - pa[i] && q + pa[i] < n && s[p - pa[i]] == s[q + pa[i]])
            pa[i]++;
        if(q + pa[i] - 1 > r) j = i;
    }
}
inline bool check(int L,int R) {
    int mid=L+R>>1;
    if ((L&1)==(R&1)) return p[mid<<1]>=R-L+2>>1;
    return p[mid<<1|1]>=R-L+1>>1;
}
inline bool Check(int L,int R) {
    int mid=L+R>>1;
    if (!check(L,mid) || !check(mid+((L&1)!=(R&1)),R)) return false;
    return true;
}
struct Palindromic_Tree {
    int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
    int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点
    int cnt[MAXN];
    int num[MAXN];
    int len[MAXN];//len[i]表示节点i表示的回文串的长度
    int S[MAXN];//存放添加的字符
    int last;//指向上一个字符所在的节点,方便下一次add
    int n;//字符数组指针
    int p;//节点指针
    int newnode(int l){//新建节点
        for(int i=0;i<N;++i) next[p][i]=0;
        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){//和KMP一样,失配后找一个尽量最长的
        while(S[n-len[x]-1]!=S[n]) x=fail[x];
        return x;
    }
    void add(int c){
        c-=a;
        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] ;//和AC自动机一样建立fail指针,以便失配后跳转
            next[cur][c]=now ;
        }
        last=next[cur][c] ;
        cnt[last]++;
        num[last]=n;
    }
    void count(){
        for(int i=p-1;i>=0;--i) cnt[fail[i]]+=cnt[i];
        //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
    }
    void get_ans(){
        for(int i=0;i<p;i++){
            if(len[i]>0){
                //cout<<num[i]<<‘ ‘<<len[i]<<‘ ‘<<num[i]-len[i]/2-1<<‘ ‘<<num[i]+len[i]/2-1<<endl;
                if(Check(num[i]-len[i],num[i]-1)){
                    ans[len[i]]+=cnt[i];
                }
            }
        }
    }
}PAM;
int main(){
    while(~scanf("%s",&s)){
        PAM.init();
        int l=strlen(s);
        for(int i=1;i<=l;i++){
            ans[i]=0;
        }
        Manacher(s,l,p);
        for(int i=0;s[i];i++){
            PAM.add(s[i]);
        }
        PAM.count();
        PAM.get_ans();
        for(int i=1;i<=l;i++){
            printf("%d",ans[i]);
            if(i!=l) printf(" ");
            else printf("\n");
        }
    }
}

 

别人的回文自动机

标签:print   out   last   return   int   tree   eps   include   count()   

原文地址:https://www.cnblogs.com/Profish/p/11296113.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!