New Distinct Substrings (后缀数组,统计有多少个不同的子串)
2016-08-15 18:16
405 查看
首先要确认一个事实:任何一个子串都是一个后缀的前缀。
根据这个,首先处理出height数组。
对于样例:ABABA
后缀数组处理出来是这样的结果。
A 0
ABA 1
ABABA 3
BA 0
BABA 2
右边的数字是height数组的值。
因为:任何一个子串都是一个后缀的前缀。 所以对于每个后缀就有 n-sa[i]个子串。
这时候从第一个后缀出来的答案是1。
然后看第二个,height是1,意味着A是和上面那个重复的,所以在计算这个的子串的时候,我们需要在这个基础上,把这个多算的A个减去。
第三个与第二个同理,height是3,意味着ABA都是重复的,所以需要减去3(ABA,AB,A 这3个多出来了)。
这个A看上去减了2遍,事实上这样做答案才会正确。因为既然这个height大于1了,就意味着第一个字符是重复的,而这个重复的字符一定在上面被算过了,所以不需要再计算。
最后的答案就是 把每个的 n-sa[i]-height[i]加了起来。
(代码中是n-1-sa[i]-height[i],这是因为对于后缀数组模板的修正,后面加一个比一切字符都小的字符)。
根据这个,首先处理出height数组。
对于样例:ABABA
后缀数组处理出来是这样的结果。
A 0
ABA 1
ABABA 3
BA 0
BABA 2
右边的数字是height数组的值。
因为:任何一个子串都是一个后缀的前缀。 所以对于每个后缀就有 n-sa[i]个子串。
这时候从第一个后缀出来的答案是1。
然后看第二个,height是1,意味着A是和上面那个重复的,所以在计算这个的子串的时候,我们需要在这个基础上,把这个多算的A个减去。
第三个与第二个同理,height是3,意味着ABA都是重复的,所以需要减去3(ABA,AB,A 这3个多出来了)。
这个A看上去减了2遍,事实上这样做答案才会正确。因为既然这个height大于1了,就意味着第一个字符是重复的,而这个重复的字符一定在上面被算过了,所以不需要再计算。
最后的答案就是 把每个的 n-sa[i]-height[i]加了起来。
(代码中是n-1-sa[i]-height[i],这是因为对于后缀数组模板的修正,后面加一个比一切字符都小的字符)。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int nMax = 1200001; char arr[nMax+1]; int sa[nMax], rank[nMax], height[nMax]; int wa[nMax], wb[nMax], wv[nMax], wd[nMax]; int n,k; int cmp(int *r, int a, int b, int l){ return r[a] == r[b] && r[a+l] == r[b+l]; } void da(char *r, int n, int m){ // 倍增算法 r为待匹配数组 n为总长度 m为字符范围 int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i; for(j = 1, p = 1; p < n; j *= 2, m = p){ for(p = 0, i = n-j; i < n; i ++) y[p ++] = i; for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j; for(i = 0; i < n; i ++) wv[i] = x[y[i]]; for(i = 0; i < m; i ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[wv[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i]; for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){ x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++; } } } void calHeight(char *r, int n){ // 求height数组。 int i, j, k = 0; for(i = 1; i <= n; i ++) { rank[sa[i]] = i; //cout<<sa[i]<<endl; } for(i = 0; i < n; height[rank[i ++]] = k){ for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++); } } int main() { int t; cin>>t; while(t--) { scanf("%s",arr); int len=strlen(arr); arr[len]=0; arr[len+1]='\0'; len++; da(arr,len,140); calHeight(arr,len-1); int ans=0; for(int i=1;i<=len-1;i++) { ans+=len-1-sa[i]-height[i]; } cout<<ans<<endl; } return 0; }
相关文章推荐
- [spoj DISUBSTR]后缀数组统计不同子串个数
- HDU3948:后缀数组+马拉车(本质不同回文子串统计)
- HDU 4436 str2int(后缀数组,一种统计n个digit字符串所有不同子串之和的方法)
- spoj 694. Distinct Substrings 后缀数组求不同子串的个数
- SPOJ 694、705 后缀数组:求不同子串
- hdu 4416 后缀自动机 问在S中有多少个不同子串满足它不是s1~sn中任意一个字符串的子串
- pku 3415 后缀数组,公共子串统计
- hdu 5769后缀数组 求含有某个字母的某个字符串的不同子串的个数
- spoj705 后缀数组求不同子串的个数
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- 【后缀数组】不同子串
- 【后缀数组】【不同子串个数】DISUBSTR spoj694/705
- HDU3518 后缀数组求不可重叠重复出现的不同子串个数
- HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)
- hdu 4622 求区间不同子串数 后缀数组|后缀自动机|字符串hash
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- SPOJ(后缀数组求不同子串个数)
- SPOJ 题目694 Distinct Substrings(后缀数组,求不同的子串个数)
- SPOJ 694 求一个字符串有多少子串 后缀数组
- Cogs 1709. [SPOJ705]不同的子串 后缀数组