【BZOJ 3238】差异 后缀自动机+树形DP

题意

给定字符串,令$s_i$表示第$i$位开始的后缀,求$\sum_{1\le i < j \le n} len(s_i)+len(s_j)-2\times lcp(s_i,s_j)$


先考虑前面的和式,直接计算为$\frac{n(n^2-1)}{2}$,考虑后面的和式,$lcp$相关可以用sam求解,sam形成的parent树是原串的前缀树,所以两个串的最长公共后缀是在parent树上最近公共祖先对应的状态的长度$maxlen_s-maxlen_{pa_s}$,将原串反向建立sam得到后缀树,parent树上每个状态的子串个数为$Right_s$,每个状态的贡献为$2\times \binom{Right_s}{2}\times (maxlen_s-maxlen_{pa_s})$,在parent树上跑一遍dp即可求出

时间复杂度$O(n)$

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1001000;
int trans[N][30], pa[N], maxlen[N], sz, root, last, Right[N];
inline void init_sam() {
    memset(trans, 0, sizeof(trans));
    root = last = sz = 1;
}
inline void extend(int c, int x) {
    int p = last, np = ++sz; last = np; maxlen[np] = x; Right[np] = 1;
    for(; p && !trans[p][c]; p = pa[p]) trans[p][c] = np;
    if(!p) {pa[np] = root; return;}
    int q = trans[p][c];
    if(maxlen[q] == maxlen[p] + 1) {
        pa[np] = q;
    }else {
        int nq = ++sz;
        memcpy(trans[nq], trans[q], sizeof(trans[q]));
        pa[nq] = pa[q]; maxlen[nq] = maxlen[p] + 1; pa[q] = pa[np] = nq;
        for(; trans[p][c] == q; p = pa[p]) trans[p][c] = nq;
    }
}
inline void build(char *s) {
    int len = strlen(s);
    for(int i = 0; i < len; ++i) extend(s[i] - 'a', i + 1);
}
int cnt, head[N], nxt[N], to[N];
inline void init_edge() {cnt = 0; memset(head, -1, sizeof(head));}
inline void add(int u, int v) {to[cnt] = v; nxt[cnt] = head[u]; head[u] = cnt++;}
LL ans = 0;
int dfs(int u) {
    for(int i = head[u]; ~i; i = nxt[i]) Right[u] += dfs(to[i]);
    ans -= 1LL * Right[u] * (Right[u] - 1) * (maxlen[u] - maxlen[pa[u]]);
    return Right[u];
}
inline void get() {
    init_edge();
    for(int i = 2; i <= sz; ++i) add(pa[i], i);
    dfs(root);
}
char str[N];
int main() {
    scanf("%s", str);
    int len = strlen(str);
    reverse(str, str + len);
    init_sam();
    build(str);
    ans = 1LL * len * (len - 1) * (len + 1) / 2;
    get();
    cout << ans << endl;
    return 0;
}
posted @ 2018-03-03 16:46  Ogiso_Setsuna  阅读(116)  评论(0编辑  收藏  举报