zoukankan      html  css  js  c++  java
  • 【BZOJ 3238】差异 后缀自动机+树形DP

    题意

    给定字符串,令$s_i$表示第$i$位开始的后缀,求$sum_{1le i < j le n} len(s_i)+len(s_j)-2 imes 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 imes inom{Right_s}{2} imes (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;
    }
    
  • 相关阅读:
    我大学时代的好朋友要结婚了!
    (function(root,factory){})(this,function($){}) 一个立即执行的匿名函数自调
    非书面的非官方的常见的HTTP请求状态码分析
    一个页面多个HTTP请求 页面卡顿!
    requestAnimationFrame Web中写动画的另一种选择
    js 点击 返回顶部 动画
    css3动画 一行字鼠标触发 hover 从左到右颜色渐变
    var 和 let 的异同?
    H5案例分享:使用JS判断客户端、浏览器、操作系统类型
    基于浏览器的HTML5地理定位
  • 原文地址:https://www.cnblogs.com/ogiso-setsuna/p/8497095.html
Copyright © 2011-2022 走看看