• 别人的回文自动机


    #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 nxt[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
        int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点
        int cnt[MAXN];
        int st[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) nxt[p][i]=0;
            cnt[p]=0;
            st[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(!nxt[cur][c]){//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
                int now=newnode(len[cur]+2) ;//新建节点
                fail[now]=nxt[get_fail(fail[cur])][c] ;//和AC自动机一样建立fail指针,以便失配后跳转
                nxt[cur][c]=now ;
            }
            last=nxt[cur][c] ;
            cnt[last]++;
            st[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){
                    if(Check(st[i]-len[i],st[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("
    ");
            }
        }
    }
  • 相关阅读:
    Vue ref
    Vue 全局注册
    【华为云技术分享】用Flask开发Web版日历应用
    【华为云技术分享】鲲鹏展翅 力算未来 | openEuler操作系统源代码正式开放
    【华为云技术分享】17张图带你解析红黑树的原理!保证你能看懂!
    【华为云技术分享】自动搭建openEuler虚拟机QEMU运行环境
    【华为云技术分享】【玩转Atlas200DK系列】应用开发之 交叉编译第三方库并在工程中使用(jsoncpp)
    【华为云技术分享】GitHub联合开发
    【华为云技术分享】【DevCloud•敏捷智库】读懂敏捷需求管理的4个关键词
    【华为云技术分享】iSulad轻量化容器实践解析
  • 原文地址:https://www.cnblogs.com/Profish/p/11296113.html
Copyright © 2020-2023  润新知