不同子串

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不同子串相关的知识,希望对你有一定的参考价值。

  题目描述:给定一个有小写英文字母构成的字符串T,求其不同子串个数

  数据范围及限制:一个串,长度不超过100000

  输入样例1:

    ababa

  输出样例1:

    9

  输入样例2

    ebvylfeicorjhpovljmgqawckptcqfuynhvnqwokvowxjgvjhztxmgzwkgvuvhsilrslnzcvmconbabwrpfniknqsimyutwstzzc

  输出样例2:

    4968

  输入样例3:

    riokzisztaydqovqjcdnojfykqjfstevddxtxbtwgzlmwqnhijuemkxaaqmjqscdpnzgseezaexluxdmdkoijafpecganbycwsjs

  输出样例3: 

    4999757677

  题解:

    因为每个子串都是某个后缀的前缀,所以想到用后缀数组,首先要知道后缀数组中height[i]的含义,height[i]不仅指排名第i的和排名第i-1的(后缀)的最长相同前缀,还指排名第i的和排名1~i-1的最长相同前缀,可以举几个例子试试。

    知道了这个性质,那么每一个后缀中只能由它得到的前缀的个数就是n-sa[i]-height[i],n-sa[i]得到这个后缀的长度(我是从0开始的),height[i]个前缀在排名1~i-1的后缀中已经得到,所以要减去,不计入答案。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long LL;
10 const LL maxn=200000;
11 LL r[maxn],sa[maxn],wa[maxn],wb[maxn],wv[maxn],Ws[maxn];
12 LL cmp(LL *r,LL a,LL b,LL l){
13     return r[a]==r[b]&&r[a+l]==r[b+l];
14 }
15 void da(LL *r,LL *sa,LL n,LL m){
16     LL i,j,p,*x=wa,*y=wb,*t;
17     for(i=0;i<m;i++) Ws[i]=0;
18     for(i=0;i<n;i++) Ws[x[i]=r[i]]++;
19     for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
20     for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i; 
21     
22     for(j=1,p=1;p<n;j*=2,m=p){
23         for(p=0,i=n-j;i<n;i++) y[p++]=i;
24         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
25         
26         for(i=0;i<n;i++) wv[i]=x[y[i]];        
27         for(i=0;i<m;i++) Ws[i]=0;
28         for(i=0;i<n;i++) Ws[wv[i]]++;
29         for(i=0;i<m;i++) Ws[i]+=Ws[i-1];
30         for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];
31         
32         for(t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1;i<n;i++)
33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
34     }
35 }
36 LL rank[maxn],height[maxn];
37 void calheight(LL *r,LL *sa,LL n){
38     LL i,j,k=0;
39     for(i=0;i<n;i++) rank[sa[i]]=i;
40     for(i=0;i<n;height[rank[i++]]=k)
41         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
42     return ;
43 }
44 char s[maxn];
45 LL num[maxn],len,ans;
46 int main(){
47     freopen("distinct.in","r",stdin);
48     freopen("distinct.out","w",stdout);
49     scanf("%s",s); len=strlen(s);
50     for(LL i=0;i<len;i++) num[i]=s[i]-a+2;
51     da(num,sa,len,30);
52     calheight(num,sa,len); height[0]=0;
53     for(LL i=0;i<len;i++){
54         LL k=len-sa[i];
55         ans+=k-height[i];
56     }
57     printf("%lld",ans);
58     return 0;
59 }

 

以上是关于不同子串的主要内容,如果未能解决你的问题,请参考以下文章

题目地址(647. 回文子串)

leetcode647 回文子串(Medium)

LQ0095 不同子串set+substring

洛谷P2679 子串

LeetCode159.至多包含两个不同字符的最长子串

NOIP2015子串[序列DP]