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

Codechef PALPROB Palindromeness 回文树

时间:2019-05-02 23:08:29      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:href   暴力   online   space   维护   %s   out   amp   oid   

传送门——Vjudge


构建出回文树,那么我们需要对于回文树的每一个节点求出它在原串中的出现次数和前\(\frac{len}{2}\)个字符构成的串

前者可以直接在fail树上传递endpos标记,后者可以倍增。但是后者还有一种复杂度\(O(?)\)的做法跑得非常快:

对于每一个点维护\(half_x\)表示点\(x\)对应的串中\(\leq \frac{len_x}{2}\)的最长的回文后缀在PAM的位置。新插入一个节点时,从它的trans的父亲的half开始,暴力跳fail直到找到当前节点的half。对于长度为\(1\)的节点单独判断一下。

所以上面的做法到底是不是\(O(n)\)的呢……

回文树一会儿不写全部忘光

#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;

const int _ = 1e5 + 7;
char s[_];
namespace PAM{
    int trans[_][26] , len[_] , fa[_] , hlf[_] , val[_] , endpos[_];
    int cnt , lst;
    
#define clr(x) memset(x , 0 , sizeof(x));
    void init(){
        cnt = 1; lst = 0;
        clr(trans); clr(len); clr(fa); clr(hlf);
        clr(val); clr(endpos);
        fa[1] = fa[0] = 1; len[1] = -1;
    }
    
    void extend(int pos){
        int p = lst;
        while(s[pos] != s[pos - len[p] - 1]) p = fa[p];
        if(trans[p][s[pos] - 'a']){
            lst = trans[p][s[pos] - 'a']; ++endpos[lst];
            return;
        }
        int k = ++cnt , q = fa[p];
        while(s[pos] != s[pos - len[q] - 1]) q = fa[q];
        fa[k] = trans[q][s[pos] - 'a']; trans[p][s[pos] - 'a'] = k;
        len[k] = len[p] + 2; lst = k; ++endpos[lst];
        if(len[k] <= 1) val[hlf[k] = k] = 1;
        else{
            p = hlf[p];
            while(s[pos - len[p] - 1] != s[pos] || len[p] + 2 > len[k] / 2)
                p = fa[p];
            hlf[k] = trans[p][s[pos] - 'a'];
            val[k] = 1 + (len[hlf[k]] == len[k] / 2 ? val[hlf[k]] : 0);
        }
    }

    long long calc(){
        for(int i = cnt ; i >= 1 ; --i)
            endpos[fa[i]] += endpos[i];
        long long ans = 0;
        for(int i = 2 ; i <= cnt ; ++i)
            ans += 1ll * val[i] * endpos[i];
        return ans;
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    int T;
    for(scanf("%d" , &T) ; T ; --T){
        scanf("%s" , s + 1); int L = strlen(s + 1);
        PAM::init();
        for(int i = 1 ; i <= L ; ++i)
            PAM::extend(i);
        cout << PAM::calc() << endl;
    }
    return 0;
}

Codechef PALPROB Palindromeness 回文树

标签:href   暴力   online   space   维护   %s   out   amp   oid   

原文地址:https://www.cnblogs.com/Itst/p/10803682.html

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