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\n",ans);
      }
      return 0;
}

  

原文地址:https://www.cnblogs.com/cutemush/p/12336866.html

时间: 2024-10-10 10:47:21

Spoj 694 Distinct Substrings的相关文章

SPOJ 694. Distinct Substrings,705. New Distinct Substrings(后缀数组)

题目大意:给定长度为N的字符串,求出其中不相同子串的个数. 解题思路:每一个字串一定是某个后缀的前缀,那么原问题就可以等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照suffix(sa[1]),suffix(sa[2])--suffix(sa[n])的顺序计算,我们会发现对于每个新加进来的后缀suffix(sa[k]),它将产生n-sa[k]+1个新的前缀.但是其中有leight[k]个是和前面的字符串的前缀是相同的.所以suffix(sa[k])加进来增加的不同的子串的个数为n-s

spoj 694 Distinct Substrings(后缀数组)

题目:求一个字符串中所有不同子串个数 后缀数组经典题,每一个子串一定是某个后缀的前缀,那么问题便等价于求所有后缀之间的不相同的前缀个数.我们按sa的顺序来考虑,当加入sa[k]的时候,sa[k]这个后缀的长度为n-sa[k]-1,那么便有n-sa[k]-1个前缀,但是由heigh数组可知sa[k]与sa[k-1]有height[k]个前缀是相同的,所以要除去. 注意的是这道题题意有点坑,一开始以为字母只能是大写的而且长度在1000之内,可发现根本不是这样!!!!!!!!最后改了m的值又把数组开到

后缀数组 SPOJ 694 Distinct Substrings

题目链接 题意:给定一个字符串,求不相同的子串的个数 分析:我们能知道后缀之间相同的前缀的长度,如果所有的后缀按照 suffix(sa[0]), suffix(sa[1]), suffix(sa[2]), …… ,suffix(sa[n])的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀.但是其中有 height[k]个是和前面的字符串的前缀是相同的.所以 suffix(sa[k])将“贡献” 出 n-sa[k]+1- heig

spoj 694 Distinct Substrings 后缀数组

题目链接 求一个字符串中不相同的子串的个数. 子串的总数是(n+1)*n/2, 减去height[i]就可以. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include

SPOJ - DISUBSTR Distinct Substrings (不相同的子串的个数)

Distinct Substrings  Time Limit: 159MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Description 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

【SPOJ】Distinct Substrings(后缀自动机)

[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/endpos\)集合的大小 但是实际上我们没有任何必要减去不合法的数量 我们只需要累加每个节点表示的合法子串的数量即可 这个值等于\(longest-shortest+1=longest-parent.longest\) #include<iostream> #include<cstdio&g

SPOJ 题目694 Distinct Substrings(后缀数组,求不同的子串个数)

DISUBSTR - Distinct Substrings no tags 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

【SPOJ】694. Distinct Substrings

http://www.spoj.com/problems/DISUBSTR/ 题意:求字符串不同子串的数目. #include <bits/stdc++.h> using namespace std; const int N=1005; void sort(int *x, int *y, int *sa, int n, int m) { static int c[N], i; for(i=0; i<m; ++i) c[i]=0; for(i=0; i<n; ++i) ++c[x[y

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi