[BZOJ3238][Ahoi2013]差异(后缀数组)
2018-01-06 22:08
239 查看
网上的题解都是后缀自动机……这里讲一下后缀数组的做法。
求出后缀数组的height数组之后,任意两个不相同的后缀的lcp,都是height数组中一段区间的最小值。
在给出的式子中,len(Ti)+len(Tj)以及系数2可以提到外面去。所以现在要求出的就是
∑1≤i<j≤nlcp(Ti,Tj)。
把求lcp转化成求height的区间最小值:
∑2≤i≤j≤nminjk=iheight[k]。
把求区间最小值之和换一个定义,改为求height中的每个位置是多少个区间的最小值。为了避免重复,这里的最小值是指数值为第一关键字,位置为第二关键字。
预处理出两个数组:
1、pre[i]:满足j<i且height[j]≤height[i]的最大的j,如果没有则为1。
2、suf[i]:满足j>i且height[j]<height[i]的最小的j,如果没有则为n+1。
这两个数组可以用一个单调的栈扫描求得。
这样就可以得出,height的第i个位置是
(i−pre[i])(suf[i]−i)个区间的最小值。因此,答案等于:
32∑ni=2i(i−1)−2∑ni=2height[i](i−pre[i])(suf[i]−i)。
代码:
求出后缀数组的height数组之后,任意两个不相同的后缀的lcp,都是height数组中一段区间的最小值。
在给出的式子中,len(Ti)+len(Tj)以及系数2可以提到外面去。所以现在要求出的就是
∑1≤i<j≤nlcp(Ti,Tj)。
把求lcp转化成求height的区间最小值:
∑2≤i≤j≤nminjk=iheight[k]。
把求区间最小值之和换一个定义,改为求height中的每个位置是多少个区间的最小值。为了避免重复,这里的最小值是指数值为第一关键字,位置为第二关键字。
预处理出两个数组:
1、pre[i]:满足j<i且height[j]≤height[i]的最大的j,如果没有则为1。
2、suf[i]:满足j>i且height[j]<height[i]的最小的j,如果没有则为n+1。
这两个数组可以用一个单调的栈扫描求得。
这样就可以得出,height的第i个位置是
(i−pre[i])(suf[i]−i)个区间的最小值。因此,答案等于:
32∑ni=2i(i−1)−2∑ni=2height[i](i−pre[i])(suf[i]−i)。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int N = 5e5 + 5; int n, sa , rank , height , w , stk , top, pre , suf ; char s ; void buildSA() { int i, k, m = 26; int *x = rank, *y = height; for (i = 1; i <= n; i++) w[x[i] = s[i] - 'a' + 1]++; for (i = 2; i <= m; i++) w[i] += w[i - 1]; for (i = 1; i <= n; i++) sa[w[x[i]]--] = i; for (k = 1; k < n; k <<= 1, swap(x, y)) { int tt = 0; for (i = n - k + 1; i <= n; i++) y[++tt] = i; for (i = 1; i <= n; i++) if (sa[i] > k) y[++tt] = sa[i] - k; memset(w, 0, sizeof(w)); for (i = 1; i <= n; i++) w[x[i]]++; for (i = 2; i <= m; i++) w[i] += w[i - 1]; for (i = n; i; i--) sa[w[x[y[i]]]--] = y[i]; m = 0; for (i = 1; i <= n; i++) { int u = sa[i], v = sa[i - 1]; y[u] = x[u] != x[v] || x[u + k] != x[v + k] ? ++m : m; } if (m == n) break; } if (y != rank) copy(y, y + n + 1, rank); height[1] = 0; for (i = 1, k = 0; i <= n; i++) { if (k) k--; int u = sa[rank[i] - 1]; while (s[i + k] == s[u + k]) k++; height[rank[i]] = k; } } int main() { int i; scanf("%s", s + 1); n = strlen(s + 1); buildSA(); stk[top = 0] = 1; for (i = 2; i <= n; i++) { while (top && height[stk[top]] > height[i]) top--; pre[stk[++top] = i] = stk[top - 1]; } stk[top = 0] = n + 1; for (i = n; i >= 2; i--) { while (top && height[stk[top]] >= height[i]) top--; suf[stk[++top] = i] = stk[top - 1]; } ll ans = 0; for (i = 2; i <= n; i++) ans += 1ll * height[i] * (i - pre[i]) * (suf[i] - i); ll tmp = 0; for (i = 2; i <= n; i++) tmp += 3ll * i * (i - 1) >> 1; cout << tmp - ans * 2 << endl; return 0; }
相关文章推荐
- 【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
- BZOJ 3238: [Ahoi2013]差异 后缀数组
- [BZOJ3238][Ahoi2013]差异(后缀数组+单调栈||后缀自动机+树形dp)
- 【bzoj3238】【AHOI2013】【差异】【后缀数组+单调栈】
- [BZOJ3238][AHOI2013]差异(后缀数组)
- 【BZOJ3238】[Ahoi2013]差异 后缀数组+单调栈
- bzoj 3238: [Ahoi2013]差异(后缀数组+单调栈)
- 【bzoj3238】差异[AHOI2013](后缀数组+单调栈)
- BZOJ 3238 [Ahoi2013]差异 后缀数组+单调栈
- bzoj 3238 [Ahoi2013]差异 后缀数组+单调栈
- 【bzoj3238】[Ahoi2013]差异 后缀数组+单调栈
- [BZOJ3238][Ahoi2013]差异解题报告|后缀数组
- [BZOJ3238][Ahoi2013]差异(后缀自动机||后缀数组)
- bzoj 3238 ahoi2013差异 后缀数组
- BZOJ 3238 [Ahoi2013]差异 后缀数组+单调栈
- bzoj3238 [Ahoi2013]差异 后缀自动机
- BZOJ_3238_[Ahoi2013]差异_后缀自动机
- BZOJ 3238 [Ahoi2013]差异(后缀自动机)
- [后缀自动机 构建后缀树 树形DP] BZOJ 3238 [Ahoi2013]差异