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.

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[i])可以产生n-sa[i]+1个前缀
但是有重复的,重复个数就是height[i]
所有不重复前缀是n-sa[i]+1-height[i]
注意第0号后缀是没法和第-1号后缀比较(因为第-1号后缀就不存在)
这样的话就会导致最后的答案少计算
这里采用的方法就是给这个字符串后面加一个未出现过的字符
这个新长度的字符串求解
 
 1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb))
5 #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2)
6 using namespace std;
7 const int N = 1005;
8 int c[N],sa[N*3];
9 int ranks[N*3], height[N*3],s[N];
10 char str[N];
11 bool pan(int *x,int i,int j,int k,int n)
12 {
13 int ti=i+k<n?x[i+k]:-1;
14 int tj=j+k<n?x[j+k]:-1;
15 return x[i]==x[j]&&ti==tj;
16 }
17 void build_SA(int n,int r)
18 {
19 int *x=ranks,*y=height;
20 for(int i=0; i<r; i++)c[i]=0;
21 for(int i=0; i<n; i++)c[s[i]]++;
22 for(int i=1; i<r; i++)c[i]+=c[i-1];
23 for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i;
24 r=1;
25 x[sa[0]]=0;
26 for(int i=1; i<n; i++)
27 x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++;
28 for(int k=1; r<n; k<<=1)
29 {
30 int yn=0;
31 for(int i=n-k; i<n; i++)y[yn++]=i;
32 for(int i=0; i<n; i++)
33 if(sa[i]>=k)y[yn++]=sa[i]-k;
34 for(int i=0; i<r; i++)c[i]=0;
35 for(int i=0; i<n; i++)++c[x[y[i]]];
36 for(int i=1; i<r; i++)c[i]+=c[i-1];
37 for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
38 swap(x,y);
39 r=1;
40 x[sa[0]]=0;
41 for(int i=1; i<n; i++)
42 x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++;
43 }
44 for(int i=0; i<n; i++)ranks[i]=x[i];
45 }
46 void get_height(int n)
47 {
48 int i,j,k=0;
49 for(i=1; i<=n; i++)ranks[sa[i]]=i;
50 for(i=0; i<n; i++)
51 {
52 if(k)k--;
53 else k=0;
54 j=sa[ranks[i]-1];
55 while(s[i+k]==s[j+k])k++;
56 height[ranks[i]]=k;
57 }
58 }
59 int main() {
60 int t;
61 scanf("%d", &t);
62 while (t--) {
63 scanf("%s", str);
64 int len = strlen(str);
65 for (int i = 0; i < len; i++)
66 s[i] = (int)str[i];
67 s[len] = 0;
68 build_SA(len+1,200);
69 get_height(len);
70 int res = 0;
71 for (int i = 1; i <= len; i++)
72 //printf("%d ",height[i]),
73 res += ((len-1) - sa[i]+1 - height[i]);
74 printf("%d\n", res);
75 }
76 return 0;
77 }
 
解法二、
先请出来一共有多少子串,即(n+1)*n/2个,然后height数组的值就是相同前缀的数量,所以用总个数减去这个字符串的所有后缀
形成的height就是结果
因为我的代码在原字符串基础上添加了一个字符,所以第0号后缀不是原字符串的,所以for循环从2到n
 
 1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb))
5 #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2)
6 using namespace std;
7 const int N = 1005;
8 int c[N],sa[N*3];
9 int ranks[N*3], height[N*3],s[N];
10 char str[N];
11 bool pan(int *x,int i,int j,int k,int n)
12 {
13 int ti=i+k<n?x[i+k]:-1;
14 int tj=j+k<n?x[j+k]:-1;
15 return x[i]==x[j]&&ti==tj;
16 }
17 void build_SA(int n,int r)
18 {
19 int *x=ranks,*y=height;
20 for(int i=0; i<r; i++)c[i]=0;
21 for(int i=0; i<n; i++)c[s[i]]++;
22 for(int i=1; i<r; i++)c[i]+=c[i-1];
23 for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i;
24 r=1;
25 x[sa[0]]=0;
26 for(int i=1; i<n; i++)
27 x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++;
28 for(int k=1; r<n; k<<=1)
29 {
30 int yn=0;
31 for(int i=n-k; i<n; i++)y[yn++]=i;
32 for(int i=0; i<n; i++)
33 if(sa[i]>=k)y[yn++]=sa[i]-k;
34 for(int i=0; i<r; i++)c[i]=0;
35 for(int i=0; i<n; i++)++c[x[y[i]]];
36 for(int i=1; i<r; i++)c[i]+=c[i-1];
37 for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
38 swap(x,y);
39 r=1;
40 x[sa[0]]=0;
41 for(int i=1; i<n; i++)
42 x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++;
43 }
44 for(int i=0; i<n; i++)ranks[i]=x[i];
45 }
46 void get_height(int n)
47 {
48 int i,j,k=0;
49 for(i=1; i<=n; i++)ranks[sa[i]]=i;
50 for(i=0; i<n; i++)
51 {
52 if(k)k--;
53 else k=0;
54 j=sa[ranks[i]-1];
55 while(s[i+k]==s[j+k])k++;
56 height[ranks[i]]=k;
57 }
58 }
59 int main()
60 {
61 int t;
62 scanf("%d", &t);
63 while (t--)
64 {
65 scanf("%s", str);
66 int len = strlen(str);
67 for (int i = 0; i < len; i++)
68 s[i] = (int)str[i];
69 s[len] = 0;
70 build_SA(len+1,200);
71 get_height(len);
72 int res = ((len+1)*len)/2;
73 for (int i = 2; i <= len; i++)
74 //printf("%d ",height[i]),
75 res -= height[i];
76 printf("%d\n", res);
77 }
78 return 0;
79 }
 

Distinct Substrings SPOJ - DISUBSTR 后缀数组的更多相关文章

  1. Distinct Substrings SPOJ - DISUBSTR(后缀数组水题)

    求不重复的子串个数 用所有的减去height就好了 推出来的... #include <iostream> #include <cstdio> #include <sst ...

  2. Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)

    Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题 ...

  3. 705. New Distinct Substrings spoj(后缀数组求所有不同子串)

    705. New Distinct Substrings Problem code: SUBST1 Given a string, we need to find the total number o ...

  4. SPOJ DISUBSTR 后缀数组

    题目链接:http://www.spoj.com/problems/DISUBSTR/en/ 题意:给定一个字符串,求不相同的子串个数. 思路:直接根据09年oi论文<<后缀数组——出来字 ...

  5. SPOJ DISUBSTR ——后缀数组

    [题目分析] 后缀数组模板题. 由于height数组存在RMQ的性质. 那么对于一个后缀,与前面相同的串总共有h[i]+sa[i]个.然后求和即可. [代码](模板来自Claris,这个板子太漂亮了) ...

  6. [spoj DISUBSTR]后缀数组统计不同子串个数

    题目链接:https://vjudge.net/contest/70655#problem/C 后缀数组的又一神奇应用.不同子串的个数,实际上就是所有后缀的不同前缀的个数. 考虑所有的后缀按照rank ...

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

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

  8. Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))

    Given a string, we need to find the total number of its distinct substrings. Input \(T-\) number of ...

  9. SPOJ694 DISUBSTR --- 后缀数组 / 后缀自动机

    SPOJ694 DISUBSTR 题目描述: Given a string, we need to find the total number of its distinct substrings. ...

随机推荐

  1. 【Spring】XML方式实现(无参构造 有参构造)和注解方式实现 IoC

    文章目录 Spring IoC的实现方式 XML方式实现 通过无参构造方法来创建 1.编写一个User实体类 2.编写我们的spring文件 3.测试类 UserTest.java 4.测试结果 通过 ...

  2. mysql .sock丢时候如何链接数据库

    在mysql服务器本机上链接mysql数据库时,经常会噢出现mysql.sock不存在,导致无法链接的问题,这是因为如果指定localhost作为一个主机名,则mysqladmin默认使用unix套接 ...

  3. WMIC 查看bios配置信息

    如何查看我们的主板上的BIOS信息呢?有办法,不用安装任何软件,只需要windows自带的命令提示符就行,哈哈 WMIC BIOS LIST FULL /FORMAT:VALUE 如果第一次使用wmi ...

  4. Table controls and tabstrip controls

    本文转载自http://www.cnblogs.com/clsoho/archive/2010/01/21/1653268.html ONTROLS Syntax Forms Declaration ...

  5. Ice系列--傻瓜式服务开发IceBox

    前言 相信大家在没有接触过框架之前,都自己或多或少的开发过一些应用服务.每个应用服务除了业务配置还有很多环境配置,资源配置等,这些跟部署相关的配置.服务跟配置文件是一种静态绑定的方式,更新配置还需要重 ...

  6. DockerFile关键字相关作用以及解释

    Dockerfile 关键字 作用 备注 FROM 指定父镜像 指定dockerfile基于那个image构建 MAINTAINER 作者信息 用来标明这个dockerfile谁写的 LABEL 标签 ...

  7. uni-app开发经验分享十二: Android平台应用启动时读写手机存储、访问设备信息(如IMEI)等权限策略及提示信息

    Android平台从6.0(API23)开始系统对权限的管理更加严格,所有涉及敏感权限都需要用户授权允许才能获取.因此一些应用基础业务逻辑需要的权限会在应用启动时申请,并引导用户允许. 读写手机存储权 ...

  8. 参数模型检验过滤器 .NetCore版

    最近学习 .NETCore3.1,发现过滤器的命名空间有变化. 除此以外一些方法的名称和使用方式也有变动,正好重写一下. 过滤器的命名空间的变化 原先:System.Web.Http.Filters; ...

  9. PCB导线长宽与电源压降

    为了计算PCB中电源线走线后的压降,需要知道PCB中使用的铜的电阻率, PCB板中的铜是直接贴上去的铜箔,因此可以当成纯铜(我问了PCB打样的厂家他们的铜的电阻率,但是他们给我说不知道,所以干脆就当成 ...

  10. JavaScript中的构造函数和原型!

    JavaScript中的原型! 原型的内容是涉及到JavaScript中的构造函数的 每一个构造函数都有一个原型对象!prototype 他的作用是 共享方法!还可以扩展内置对象[对原来的内置对象进行 ...