CF17E Palisection

题意

给定一个长度为n的小写字母串。问你有多少对相交的回文子串(包含也算相交)
相交的回文子串个数 mod 51123987 m o d   51123987

Sol

求相交的回文子串不太好求
考虑用总数减去不相交的回文串个数
那么考虑求以一个点结尾的后缀回文串的贡献:
就是以它后面的点为开头的前缀回文串的个数
正反两遍回文树求一下就好了

# include 
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

const int maxn(2e6 + 5);
const int mod(51123987);

int first[maxn], nxt[maxn], type[maxn], fa[maxn], deep[maxn], pre[maxn], len[maxn];
int tot, last, ans, n;
char s[maxn];

IL void Upd(RG int &x, RG int y){
    x += y;
    if(x >= mod) x -= mod;
}

IL int NewNode(){
    first[++tot] = len[tot] = fa[tot] = deep[tot] = nxt[tot] = 0;
    type[tot] = -1;
    return tot;
}

IL void Init(){
    first[1] = first[0] = nxt[1] = nxt[0] = 0, type[0] = type[1] = -1;
    fa[0] = fa[1] = 1, tot = 1, last = 0, len[1] = -1;
}

IL int Son(RG int u, RG int c){
    for(RG int v = first[u]; v; v = nxt[v])
        if(type[v] == c) return v;
    return 0;
}

IL void Link(RG int u, RG int v, RG int c){
    nxt[v] = first[u], first[u] = v, type[v] = c;
}

IL void Extend(RG int pos, RG int c){
    RG int p = last;
    while(s[pos - len[p] - 1] != s[pos]) p = fa[p];
    if(!Son(p, c)){
        RG int np = NewNode(), q = fa[p];
        while(s[pos - len[q] - 1] != s[pos]) q = fa[q];
        len[np] = len[p] + 2, fa[np] = Son(q, c);
        Link(p, np, c), deep[np] = deep[fa[np]] + 1;
    }
    last = Son(p, c);
}

int main(){
    n = Input(), scanf(" %s", s + 1), Init();
    for(RG int i = 1; i <= n; ++i){
        Extend(i, s[i] - 'a');
        pre[i] = deep[last], Upd(pre[i], pre[i - 1]);
        Upd(ans, deep[last]);
    }
    ans = (1LL * ans * (ans - 1) >> 1) % mod;
    reverse(s + 1, s + n + 1), Init();
    for(RG int i = 1; i <= n; ++i){
        Extend(i, s[i] - 'a');
        Upd(ans, mod - 1LL * deep[last] * pre[n - i] % mod);
    }
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(回文树)