Spoj 694 Distinct Substrings

Posted cutemush

tags:

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

Given a string, we need to find the total number of its distinct substrings.

给你一个字符中,统计有多少个不同的子串
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.
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.

 

Sol:

某个子串一定是某个后缀的前缀, 那么原问题等价于求所有后缀之间的不相
同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),
suffix(sa[3]), …… ,suffix(sa[n])的顺序计算, 不难发现, 对于每一次新加
进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀。但是其中有
height[k]个是和前面的字符串的前缀是相同的。所以suffix(sa[k])将“ 贡献”
出n-sa[k]+1- height[k]个不同的子串。累加后便是原问题的答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 2005
using namespace std;
 
char st[1001];
int ca,n,ans,tot,tmp[maxn],rankk[maxn],sa[maxn],sum[maxn],hei[maxn];
 
int main(){
      scanf("%d",&ca);
      while (ca--){
                scanf("%s",st+1);
                n=strlen(st+1);
                memset(sum,0,sizeof(sum));
                for (int i=1;i<=n;i++) sum[tmp[i]=st[i]]++;
                for (int i=1;i<=256;i++) sum[i]+=sum[i-1];
                for (int i=n;i>=1;i--) sa[sum[tmp[i]]--]=i;
                tot=0;
                rankk[sa[1]]=++tot;
                for (int i=2;i<=n;i++){
                       if (tmp[sa[i]]!=tmp[sa[i-1]]) tot++;
                       rankk[sa[i]]=tot;
                }
                for (int len=1;len<=n;len<<=1){
                           memset(sum,0,sizeof(sum));
                           for (int i=1;i<=n;i++) sum[rankk[i+len]]++;
                           for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
                           for (int i=n;i>=1;i--) tmp[sum[rankk[i+len]]--]=i;
                           memset(sum,0,sizeof(sum));
                           for (int i=1;i<=n;i++) sum[rankk[i]]++;
                           for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
                           for (int i=n;i>=1;i--) sa[sum[rankk[tmp[i]]]--]=tmp[i];
                           tot=0;
                           tmp[sa[1]]=++tot;
                           for (int i=2;i<=n;i++){
                                   if (rankk[sa[i]]!=rankk[sa[i-1]]||rankk[sa[i]+len]!=rankk[sa[i-1]+len]) tot++;
                                   tmp[sa[i]]=tot;
                           }
                           for (int i=1;i<=n;i++) rankk[i]=tmp[i];
                }
                hei[1]=0;
                for (int i=1,j=0;i<=n;i++){
                           if (rankk[i]==1) continue;
                           while (st[i+j]==st[sa[rankk[i]-1]+j]) j++;
                           hei[rankk[i]]=j;
                           if (j) j--;
                }
                ans=n;
                for (int i=2;i<=n;i++){
                       ans+=(n-i+1);
                       ans-=hei[i];
                }
                printf("%d
",ans);
      }
      return 0;
}

  

以上是关于Spoj 694 Distinct Substrings的主要内容,如果未能解决你的问题,请参考以下文章

Distinct Substrings(spoj 694)

spoj694 DISUBSTR - Distinct Substrings

SPOJ694&705Distinct Substrings(后缀数组)

SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )

spoj 694 求一个字符串中不同子串的个数

SPOJ 694 不同子串个数