题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的时候,所以思路就是先找出每个节点被几个后缀经过,这显然把边反转倒着找就可以了,然后他会被出现次数sz个串经过. 出现次数等于parent树子树中np类节点的个数,这跑个dfs就好了,一个相同前缀产生的贡献是sz*(sz-1)/2 然后思考一个点可能代表多个子串,但是他们的出现次数都是相同的,所以单个…
题目大意:给一个长度为$n$的字符串,求: $$\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|-2\times lcp(suf_i,suf_j)$$ 题解:建一棵后缀树,这个式子就成了后缀树上所有后缀之间的距离(后缀树可以把字符串反着加入后缀自动机得到的$fail$数组而来),然后有两种做法: 1. 把$\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|$直接求出来$$\be…
3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2512  Solved: 1140[Submit][Status][Discuss] Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 后缀数组看这里 http://www.cnblogs.com/candy99/p/6250732.html 反串建SAM然后Parent Tree就是后缀树了 后缀树上两点的LCP…
题中要求: $\sum_{1\leqslant i < j \leq n } Len(T_{i}) +Len(T_{j})-2LCP(T_{i},T_{j})$ 公式左边的部分很好求,是一个常量,关键在于如何求取右边的 $2*LCP(T_{i},T_{j})$ 在后缀自动机中,任意两个字符串所代表的节点在 $Parent$ 树中的公共祖先所代表的字符串一 定为两个字符串的最长公共后缀, 我们想求最长公共前缀,将字符串倒着插入即可. 一次考虑每个点作为公共祖先能贡献的值: 我们要使答案不重复,不遗…
/* 前面的那一坨是可以O1计算的 后面那个显然后缀数组单调栈比较好写??? 两个后缀的lcp长度相当于他们在后缀树上的lca的深度 那么我们就能够反向用后缀自动机构造出后缀树然后统计每个点作为lca的情况和即可 */ #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #define ll long long #def…
Brief Description Algorithm Design 下面给出后缀自动机的一个性质: 两个子串的最长公共后缀,位于这两个串对应的状态在parent树上的lca状态上.并且最长公共后缀的长度就是lca状态的len. 证明:对于一个串,他的所有祖先节点都是他的后缀,并且深度越大,长度越长,由此不难说明两个子串的最长公共后缀一定在lca状态上.考察这个lca,他代表的所有子串一定都是两个子串的公共后缀,我们直接取最大的就可以了. 有了这个性质,我们就可以开始乱搞了. Code #inc…
后缀自动机的parent树就是反串的后缀树. 所以只需要反向构建出后缀树,就可以乱搞了. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #…
补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); 那么我们考虑剩下的部分应该怎么求解! 首先这里有一个性质.对于任意两个后缀\(i,j\),他们的\(lcp\)长度是他们对应的\(rank\)之间的\(height\)的\(min\) (左开右闭) 或者这样说 \(lcp(i,j) = min(height[rank[i]+1],height[rank[…
题目链接 \(Description\) \(Solution\) len(Ti)+len(Tj)可以直接算出来,每个小于n的长度会被计算n-1次. \[\sum_{i=1}^n\sum_{j=i+1}^n i+j = (n-1)*\sum_{i=1}^n = (n-1)*\frac{n*(n+1)}{2}\] 对于后半部分: SAM:求后缀的LCP,我们可以想到将字符串反转,求前缀的最长公共后缀. parent树上每个叶子节点都对应一个前缀,两个节点间的最长公共后缀在它们的LCA处,长度为le…
题意 题目链接 Sol 前面的可以直接算 然后原串翻转过来,这时候变成了求任意两个前缀的最长公共后缀,显然这个值应该是\(len[lca]\),求出\(siz\)乱搞一下 #include<bits/stdc++.h> #define int long long #define LL long long using namespace std; const int MAXN = 1e6 + 10; LL N; char a[MAXN]; int fa[MAXN], len[MAXN], siz…