「Codechef April Lunchtime 2015」Palindromeness

Posted mangoyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「Codechef April Lunchtime 2015」Palindromeness相关的知识,希望对你有一定的参考价值。

「Codechef April Lunchtime 2015」Palindromeness

解题思路 :

考虑对于回文子串 (s) 贡献的定义:
[ value_s = [ s[1,lfloor frac{|s|}{2} floor] ext{ is palindrome}] imes value_{s[1,lfloor frac{|s|}{2} floor]} + 1 ]
也就是说对于每一个回文子串,只需要判断其前一半的字符是不是回文串并得到贡献即可。

于是建出回文树,可以通过跳 (fail) 得到其所有回文前缀,用倍增找到第一个长度小于等于一半的回文前缀,判断其长度是否恰好是一半并继承贡献。

(size_u) 表示回文树上一个节点所代表的回文串的 (right) 集合大小,则
[ Ans =sum_{u ext{ in pam}} size_u imes value_u ]
总复杂度 (O(|s|log|s|))

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((int)(1e9))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int N = 200005;
char s[N];
namespace PAM{
    ll ans;
    int ch[N][26], sz[N], fa[N], len[N], f[N][21], val[N], size, tail;
    inline int newnode(int x){ return len[++size] = x, size; }
    inline void init(){ 
        memset(ch, 0, sizeof(ch));
        memset(fa, 0, sizeof(fa));
        memset(sz, 0, sizeof(sz));
        len[1] = -1, fa[0] = 1, size = tail = 1, ans = 0; 
    }
    inline void pushback(int pos){
        int c = s[pos] - 'a', p = tail;
        while(s[pos-len[p]-1] != s[pos]) p = fa[p];
        if(ch[p][c]) return (void) (sz[tail=ch[p][c]]++);
        int np = newnode(len[p] + 2), u = fa[p];
        while(s[pos-len[u]-1] != s[pos]) u = fa[u];
        fa[np] = ch[u][c], sz[tail=ch[p][c]=np]++;
    }
    inline void solve(){
        for(int i = 1; i <= size; i++) f[i][0] = fa[i];
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i <= size; i++)
                f[i][j] = f[f[i][j-1]][j-1];
        for(int i = 2; i <= size; i++){
            val[i] = 1; int x = i;
            for(int j = 20; ~j; j--) 
                if(len[f[x][j]] >= len[i] / 2) x = f[x][j]; 
            if(len[x] == len[i] / 2) val[i] += val[x];
        }
        for(int i = size; i > 2; i--) sz[fa[i]] += sz[i]; 
        for(int i = 2; i <= size; i++) ans += 1ll * val[i] * sz[i];
        cout << ans << endl;
    }
}
int main(){
    int T; read(T);
    while(T--){
        scanf("%s", s + 1); int n = strlen(s + 1);
        PAM::init();
        for(int i = 1; i <= n; i++) PAM::pushback(i);
        PAM::solve();
    }
    return 0;
}

以上是关于「Codechef April Lunchtime 2015」Palindromeness的主要内容,如果未能解决你的问题,请参考以下文章

CodeChef April Challenge 2019题解

codechef April Challenge 2018 Div2(1-4)

Codechef APRIL14 ANUCBC Cards, bags and coins 题解

分段错误:为什么这里的数组索引超出范围?

Codechef 虫洞:我的逻辑有啥问题?

Codechef RIN 「Codechef14DEC」Course Selection 最小割离散变量模型