「Codechef April Lunchtime 2015」Palindromeness

「Codechef April Lunchtime 2015」Palindromeness

解题思路 :

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

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

\(size_u\) 表示回文树上一个节点所代表的回文串的 \(right\) 集合大小,则
\[ Ans =\sum_{u \text{ in pam}} size_u \times 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;
}

猜你喜欢

转载自www.cnblogs.com/mangoyang/p/10165325.html