【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;
}

原文地址:https://www.cnblogs.com/ogiso-setsuna/p/8497095.html

时间: 2024-08-02 05:23:36

【BZOJ 3238】差异 后缀自动机+树形DP的相关文章

BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢). 看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作. 1 /********************************************************

[BZOJ 4033] [HAOI2015] T1 【树形DP】

题目链接:BZOJ - 4033 题目分析 使用树形DP,用 f[i][j] 表示在以 i 为根的子树,有 j 个黑点的最大权值. 这个权值指的是,这个子树内部的点对间距离的贡献,以及 i 和 Father[i] 之间的边对答案的贡献(比如这条边对黑点对距离和的贡献就是子树内部的黑点数 * 子树外部的黑点数 * 这条边的权值). 然后DFS来求,枚举 i 的每个儿子 j,现在的 f[i][] 是包含了 [1, j-1] 子树,然后两重循环枚举范围是 [1, j - 1] 的子树总 Size 和

bzoj 3566: [SHOI2014]概率充电器 树形DP

首先普及一个概率公式 P(A+B)=P(A)+P(B)-P(AB) 题意:一些充电元件和导线构成一棵树,充电元件是否能充电有2种情况, 1.它自己有qi%的概率充电 2.与它相邻的元件通过导线给它充电(导线有p%的概率导通) 求最终充了电的元件的期望 题解:首先可以将元件能否充电分成3种情况考虑, 1.它自己给自己充好了电 2.它的儿子方向给它传送了电 3.它的父亲方向给它传送了电. 对于1,题目已经给出可以直接赋值, 对于2,可以通过一次树的深度遍历求得.pson[now]=pson[now]

BZOJ 2878([Noi2012]迷失游乐园-树形DP+环加外向树+期望DP+vector的erase)

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved: 223 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

BZOJ 3238 AHOI2013 差异 后缀自动机

题目大意:给定一个字符串,求Σ[1<=i<j<=n]|Ti|+|Tj|-2|LCP(Ti,Tj)| 前两项是可以O(1)求的 我们要求的就是LCP之和 对反串建立后缀自动机 那么parent指针连成的树就是后缀树 直接在后缀树上DP就行- - 对于每个节点统计所有子树两两right集合大小乘积之和乘上这个节点的深度即可 QY神在学校讲了一天的SAM... 现在我觉得我还是回去学大型建筑机械吧233- - #include <map> #include <vector&g

bzoj 3238差异

3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1420  Solved: 662[Submit][Status][Discuss] Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N<=500000,S由小写英文字母组成 题解: right集合:pnt树上的子树sz大小(

【BZOJ3238】【Ahoi2013】差异 后缀自动机

转载请注明出处谢谢..http://blog.csdn.net/vmurder/article/details/42721101 首先 秦神QY Orz 题解: 这道题后缀数组过于鬼畜(wo'tai'ruo'bu'gan'xie) 所以写了简单好写易于理解不用分治不用RMQ的SAM大叔. 题解: 首先其实我们需要一个后缀树,然后两个后缀的lcp就是它们lca的len. 后缀树可以通过反序后缀自动机得到,这个很水. 然后len的性质就是后缀自动机的那个len(我写的'deep'). 后缀树上DP就

【BZOJ2806】【CTSC2012】Cheat 广义后缀自动机+二分+Dp

题目 题目在这里 思路&做法 我们先对标准作文库建广义后缀自动机. 然后对于每一篇阿米巴的作文, 我们首先把放到广义后缀自动机跑一遍, 对于每一个位置, 记录公共子串的长度\((\)即代码和下文中的\(val\)数组\()\) 接着我们二分答案, 用DP检验. Dp方程很好想, \(d_i = max \{ d_j + i - j \ | \ i-val_i <= j <= i-lim \}\) 可以用单点队列优化. 代码 #include <iostream> #incl

BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )

一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. --------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm&