SPOJ DISUBSTR - Distinct Substrings(不同子串数量 后缀数组)
2017-09-29 20:02
736 查看
Given a string, we need to find the total number of its distinct substrings.
Each test case consists of one string, whose length is <= 1000
2
CCCCC
ABABA
Sample Output:
5
9
Explanation for the testcase with string ABABA:
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.
每个子串一定是某个后缀的前缀, 那么原问题等价于求所有后缀之间的不相
同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),suffix(sa[3]), ...... ,suffix(sa
)的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀。但是其中有height[k]个是和前面的字符串的前缀是相同的。 所以 suffix(sa[k])将“贡献”出
n-sa[k]+1- height[k]个不同的子串。累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。
Input
T- number of test cases. T<=20;Each test case consists of one string, whose length is <= 1000
Output
For each test case output one number saying the number of distinct substrings.Example
Sample Input:2
CCCCC
ABABA
Sample Output:
5
9
Explanation for the testcase with string ABABA:
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.
每个子串一定是某个后缀的前缀, 那么原问题等价于求所有后缀之间的不相
同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),suffix(sa[3]), ...... ,suffix(sa
)的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀。但是其中有height[k]个是和前面的字符串的前缀是相同的。 所以 suffix(sa[k])将“贡献”出
n-sa[k]+1- height[k]个不同的子串。累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <queue> #include <math.h> #include <vector> using namespace std; const int maxn = 1111; int cnt[maxn],sa[maxn],height[maxn],res[maxn],rk[maxn],w[maxn]; void getSa(int len,int up) { int *k=rk,*r=res,*id=height; for(int i=0;i<up;i++) cnt[i]=0; for(int i=0;i<len;i++) cnt[k[i]=w[i]]++; for(int i=0;i<up;i++) cnt[i+1]+=cnt[i]; for(int i=len-1;i>=0;i--){ sa[--cnt[k[i]]]=i; } int d=1,p=0; while(p<len){ for(int i=len-d;i<len;i++) id[p++]=i; for(int i=0;i<len;i++) if(sa[i]-d>=0) id[p++]=sa[i]-d; for(int i=0;i<len;i++) r[i]=k[id[i]]; for(int i=0;i<up;i++) cnt[i]=0; for(int i=0;i<len;i++) cnt[r[i]]++; for(int i=0;i<up;i++) cnt[i+1]+=cnt[i]; for(int i=len-1;i>=0;i--){ sa[--cnt[r[i]]]=id[i]; } p=0; swap(k,r); k[sa[0]]=p++; for(int i=0;i<len-1;i++){ if(sa[i]+d<len&&sa[i+1]+d<len&&r[sa[i]]==r[sa[i+1]]&&r[sa[i+1]+d]==r[sa[i]+d]){ k[sa[i+1]]=p-1; } else k[sa[i+1]]=p++; } if(p>=len) return; d=d*2,up=p,p=0; } } void getHeight(int len) { for(int i=0;i<len;i++) rk[sa[i]]=i; height[1]=0; for(int i=0,p=0;i<len-1;i++){ int j=sa[rk[i]-1]; while(i+p<len&&j+p<len&&w[i+p]==w[j+p]) p++; height[rk[i]]=p; p=max(0,p-1); } } void getSuffix(char s[]) { int len=(int)strlen(s); for(int i=0;i<len;i++){ w[i]=s[i]; } w[len++]=0; getSa(len,400); getHeight(len); } void doit(char s[]) { int len=strlen(s); int ans=0; for(int i=1;i<=len;i++){ ans+=len-sa[i]-height[i]; } printf("%d\n",ans); } int main() { int T; scanf("%d",&T); for(int i=1;i<=T;i++){ char s[maxn]; scanf("%s",s); getSuffix(s); doit(s); } }
相关文章推荐
- Distinct Substrings SPOJ - DISUBSTR 后缀数组(计算不同的子串数目)
- [spoj DISUBSTR]后缀数组统计不同子串个数
- SPOJ DISUBSTR - Distinct Substrings or SUBST1 - New Distinct Substrings 【不同子串数目】
- SPOJ - DISUBSTR 多少个不同的子串
- SPOJ - DISUBSTR 多少个不同的子串
- SPOJ DISUBSTR 后缀数组
- [SPOJ DISUBSTR]Distinct Substrings(后缀数组)
- SPOJ DISUBSTR Distinct Substrings(后缀数组)
- SPOJ DISUBSTR-----后缀数组求串的子串的个数
- spoj 694 DISUBSTR - Distinct Substrings (后缀数组)
- SPOJ - DISUBSTR Distinct Substrings(后缀数组求不相同的子串个数)
- SPOJ 694 / SPOJ DISUBSTR Distinct Substrings【后缀数组】不相同的子串的个数
- SPOJ DISUBSTR(后缀数组)
- spoj 705 求不同子串的个数(后缀数组)
- SPOJ - DISUBSTR (后缀数组)
- [SPOJ705]DISUBSTR(后缀数组)
- SPOJ-694-求字符串中不同子串个数(后缀数组)
- SPOJ694&&SPOJ705 DISUBSTR - Distinct Substrings && SUBST1 - New Distinct Substrings 后缀数组
- SPOJ DISUBSTR - Distinct Substrings(后缀数组[不相同的子串的个数])
- SPOJ694--- DISUBSTR - Distinct Substrings(后缀数组)