[TyvjP1515] 子串统计 [luoguP2408] 不同子串个数(后缀数组)
2017-06-12 08:58
351 查看
经典题
统计一个字符串中不同子串的个数
一个字符串中的所有子串就是所有后缀的前缀
先求出后缀数组,求出后缀数组中相邻两后缀的 lcp
那么按照后缀数组中的顺序遍历求解
每一个后缀 suffix(sa[i]) 对于答案的贡献为 len - sa[i] - height[i]
len - sa[i] 为当前后缀的长度,也就是当前后缀所有前缀的个数(字符串从 0 开始)
height[i] 就是相邻两后缀 lcp,因为有可能会有相同前缀,而相同前缀在前面已经计算过了
为什么只需要 height 数组,而不用把任意两后缀的 lcp 求出来呢?
因为所有后缀已经按照字典序排序了,也就是说,sa[i] 和 sa[i - 1] 的 lcp 即为 sa[i] 和 sa[0 ~ i - 1] 的所有 lcp 的最大值。
——代码(Tyvj)
#include <cstdio> #include <cstring> #include <iostream> #define N 200001 #define LL long long LL ans; int len, m = 256; int buc , x , y , sa , rank , height ; char s ; inline void build_sa() { int i, k, p; for(i = 0; i < m; i++) buc[i] = 0; for(i = 0; i < len; i++) buc[x[i] = s[i]]++; for(i = 1; i < m; i++) buc[i] += buc[i - 1]; for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i; for(k = 1; k <= len; k <<= 1) { p = 0; for(i = len - 1; i >= len - k; i--) y[p++] = i; for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k; for(i = 0; i < m; i++) buc[i] = 0; for(i = 0; i < len; i++) buc[x[y[i]]]++; for(i = 1; i < m; i++) buc[i] += buc[i - 1]; for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i]; std::swap(x, y); p = 1, x[sa[0]] = 0; for(i = 1; i < len; i++) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++; if(p >= len) break; m = p; } } inline void build_height() { int i, j, k = 0; for(i = 0; i < len; i++) rank[sa[i]] = i; for(i = 0; i < len; i++) { if(!rank[i]) continue; if(k) k--; j = sa[rank[i] - 1]; while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++; height[rank[i]] = k; } } int main() { int i; scanf("%d", &len); getchar(); for(i = 0; i < len; i++) { s[i] = getchar(); if((i + 1) % 80 == 0) getchar(); } build_sa(); build_height(); for(i = 0; i < len; i++) ans += (LL)(len - sa[i] - height[i]); printf("%lld\n", ans); return 0; }View Code
洛谷那题好像数据有点问题。
相关文章推荐
- spoj694 Distinct Substrings(后缀数组+统计不同子串的个数)
- hdu3948——后缀数组统计不同回文子串的个数
- spoj 694 Distinct Substrings(求不同的子串个数,后缀数组基础题)
- HDU3948:后缀数组+马拉车(本质不同回文子串统计)
- Distinct Substrings SPOJ - DISUBSTR 后缀数组(计算不同的子串数目)
- 有多少个不同的子串?-- 后缀数组
- SPOJ DISUBSTR - Distinct Substrings(不同子串数量 后缀数组)
- 有多少个不同的子串?-- 后缀数组
- New Distinct Substrings (后缀数组,统计有多少个不同的子串)
- [spoj DISUBSTR]后缀数组统计不同子串个数
- spoj 705 求不同子串的个数(后缀数组)
- SPOJ-694-求字符串中不同子串个数(后缀数组)
- HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)
- spoj 405 求不同子串的个数 后缀数组和高度数组的应用
- SPOJ 694 求不同子串数 后缀数组
- hdu 1544 统计回文子串的个数
- HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)
- 后缀数组(模板题) - 求最长公共子串 - poj 2774 Long Long Message
- C# 实现统计字符串中不同单词的出现次数【百度笔试题】
- spoj694 不相同的子串的个数(后缀数组)