题意:求字符串中不同子串的个数。

解题关键:每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。

1、总数减去height数组的和即可。

注意这里height中为什么不需要进行组合计数,因为,每一个height的左端点已经确定,所以只需变动右端点,总共$height[i]$种情况。

2、如果所有的后缀按照 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]个不同的子串。累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。

类似于dp的过程

法一:

  1. #include <cstdlib>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #include<iostream>
  6. #include<cmath>
  7. #define inf 0x3f3f3f3f
  8. typedef long long ll;
  9. using namespace std;
  10. const int N=;
  11. int wa[N],wb[N],wv[N],wc[N];
  12. bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
  13. void make_sa(int *r,int *sa,int n,int m){
  14. int i,j,p,*x=wa,*y=wb;
  15. for(i=;i<m;i++) wc[i]=;
  16. for(i=;i<n;i++) wc[x[i]=r[i]]++;
  17. for(i=;i<m;i++) wc[i]+=wc[i-];
  18. for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
  19. for(j=,p=;p<n;j*=,m=p){
  20. for(p=,i=n-j;i<n;i++) y[p++]=i;
  21. for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
  22. for(i=;i<n;i++) wv[i]=x[y[i]];
  23. for(i=;i<m;i++) wc[i]=;
  24. for(i=;i<n;i++) wc[wv[i]]++;
  25. for(i=;i<m;i++) wc[i]+=wc[i-];
  26. for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
  27. for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
  28. }
  29. return;
  30. }
  31. int rank1[N],height[N],sa[N];
  32. void make_height(int *r,int *sa,int n){
  33. int i,j,k=;
  34. for(i=;i<=n;i++) rank1[sa[i]]=i;
  35. for(i=;i<n;height[rank1[i++]]=k)
  36. for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
  37. return;
  38. }
  39.  
  40. int n,k,r[N];
  41. int main(){
  42. int t;
  43. ios::sync_with_stdio();
  44. cin>>t;
  45. while(t--){
  46. string s;
  47. cin>>s;
  48. for(int i=;i<s.size();i++) r[i]=(int)s[i];
  49. r[s.size()]=;
  50. n=s.size();
  51. make_sa(r,sa,n+,);
  52. make_height(r,sa,n);
  53. ll sum=s.size()*(s.size()+)/;
  54. for(int i=;i<=n;i++){
  55. sum-=height[i];
  56. }
  57. cout<<sum<<"\n";
  58. }
  59. return ;
  60. }

法二:

  1. #include <cstdlib>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. #include<iostream>
  6. #include<cmath>
  7. #define inf 0x3f3f3f3f
  8. typedef long long ll;
  9. using namespace std;
  10. const int N=;
  11. int wa[N],wb[N],wv[N],wc[N];
  12. bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
  13. void make_sa(int *r,int *sa,int n,int m){
  14. int i,j,p,*x=wa,*y=wb;
  15. for(i=;i<m;i++) wc[i]=;
  16. for(i=;i<n;i++) wc[x[i]=r[i]]++;
  17. for(i=;i<m;i++) wc[i]+=wc[i-];
  18. for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
  19. for(j=,p=;p<n;j*=,m=p){
  20. for(p=,i=n-j;i<n;i++) y[p++]=i;
  21. for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
  22. for(i=;i<n;i++) wv[i]=x[y[i]];
  23. for(i=;i<m;i++) wc[i]=;
  24. for(i=;i<n;i++) wc[wv[i]]++;
  25. for(i=;i<m;i++) wc[i]+=wc[i-];
  26. for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
  27. for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
  28. }
  29. return;
  30. }
  31. int rank1[N],height[N],sa[N];
  32. void make_height(int *r,int *sa,int n){
  33. int i,j,k=;
  34. for(i=;i<=n;i++) rank1[sa[i]]=i;
  35. for(i=;i<n;height[rank1[i++]]=k)
  36. for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
  37. return;
  38. }
  39.  
  40. int n,k,r[N];
  41. int main(){
  42. int t;
  43. ios::sync_with_stdio();
  44. cin>>t;
  45. while(t--){
  46. string s;
  47. cin>>s;
  48. for(int i=;i<s.size();i++) r[i]=(int)s[i];
  49. r[s.size()]=;
  50. n=s.size();
  51. make_sa(r,sa,n+,);
  52. make_height(r,sa,n);
  53. int sum=;
  54. for(int i=;i<=n;i++){
  55. sum+=n-sa[i]-height[i];
  56. }
  57. cout<<sum<<"\n";
  58. }
  59. return ;
  60. }

另:整理下DC3模板(r和sa

  1. #include<cstdlib>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<iostream>
  6. #include<cmath>
  7. #define inf 0x3f3f3f3f
  8. typedef long long ll;
  9. using namespace std;
  10. const int N=;
  11. #define F(x) ((x)/3+((x)%3==1?0:tb))
  12. #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
  13. int wa[N],wb[N],wv[N],ws1[N];
  14. int c0(int *r,int a,int b){ return r[a]==r[b]&&r[a+]==r[b+]&&r[a+]==r[b+]; }
  15. int c12(int k,int *r,int a,int b){
  16. if(k==) return r[a]<r[b]||r[a]==r[b]&&c12(,r,a+,b+);
  17. else return r[a]<r[b]||r[a]==r[b]&&wv[a+]<wv[b+];
  18. }
  19. void sort(int *r,int *a,int *b,int n,int m){
  20. int i;
  21. for(i=;i<n;i++) wv[i]=r[a[i]];
  22. for(i=;i<m;i++) ws1[i]=;
  23. for(i=;i<n;i++) ws1[wv[i]]++;
  24. for(i=;i<m;i++) ws1[i]+=ws1[i-];
  25. for(i=n-;i>=;i--) b[--ws1[wv[i]]]=a[i];
  26. return;
  27. }
  28. void dc3(int *r,int *sa,int n,int m){
  29. int i,j,*rn=r+n,*san=sa+n,ta=,tb=(n+)/,tbc=,p;
  30. r[n]=r[n+]=;
  31. for(i=;i<n;i++) if(i%!=) wa[tbc++]=i;
  32. sort(r+,wa,wb,tbc,m);
  33. sort(r+,wb,wa,tbc,m);
  34. sort(r,wa,wb,tbc,m);
  35. for(p=,rn[F(wb[])]=,i=;i<tbc;i++)
  36. rn[F(wb[i])]=c0(r,wb[i-],wb[i])?p-:p++;
  37. if(p<tbc) dc3(rn,san,tbc,p);
  38. else for(i=;i<tbc;i++) san[rn[i]]=i;
  39. for(i=;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*;
  40. if(n%==) wb[ta++]=n-;
  41. sort(r,wb,wa,ta,m);
  42. for(i=;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
  43. for(i=,j=,p=;i<ta && j<tbc;p++)
  44. sa[p]=c12(wb[j]%,r,wa[i],wb[j])?wa[i++]:wb[j++];
  45. for(;i<ta;p++) sa[p]=wa[i++];
  46. for(;j<tbc;p++) sa[p]=wb[j++];
  47. return;
  48. }
  49. int rank1[N],height[N],sa[*N];
  50. void make_height(int *r,int *sa,int n){
  51. int i,j,k=;
  52. for(i=;i<=n;i++) rank1[sa[i]]=i;
  53. for(i=;i<n;height[rank1[i++]]=k)
  54. for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
  55. return;
  56. }
  57.  
  58. int n,k,r[*N];
  59. int main(){
  60. int t;
  61. ios::sync_with_stdio();
  62. cin>>t;
  63. while(t--){
  64. string s;
  65. cin>>s;
  66. for(int i=;i<s.size();i++) r[i]=(int)s[i];
  67. r[s.size()]=;
  68. n=s.size();
  69. dc3(r,sa,n+,);
  70. make_height(r,sa,n);
  71. int sum=;
  72. for(int i=;i<=n;i++){
  73. sum+=n-sa[i]-height[i];
  74. }
  75. cout<<sum<<"\n";
  76. }
  77. return ;
  78. }

必须开到3倍大小)

[spoj694&spoj705]New Distinct Substrings(后缀数组)的更多相关文章

  1. SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数

    题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...

  2. SPOJ - DISUBSTR Distinct Substrings (后缀数组)

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

  3. 【SPOJ – SUBST1】New Distinct Substrings 后缀数组

    New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...

  4. SPOJ DISUBSTR Distinct Substrings 后缀数组

    题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...

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

    题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀 ...

  6. spoj Distinct Substrings 后缀数组

    给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和 ...

  7. spoj 694. Distinct Substrings 后缀数组求不同子串的个数

    题目链接:http://www.spoj.com/problems/DISUBSTR/ 思路: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照su ...

  8. SPOJ_705_New Distinct Substrings_后缀数组

    SPOJ_705_New Distinct Substrings_后缀数组 题意: 给定一个字符串,求该字符串含有的本质不同的子串数量. 后缀数组的一个小应用. 考虑每个后缀的贡献,如果不要求本质不同 ...

  9. Cogs 1709. [SPOJ705]不同的子串 后缀数组

    题目:http://cojs.tk/cogs/problem/problem.php?pid=1709 1709. [SPOJ705]不同的子串 ★★   输入文件:subst1.in   输出文件: ...

随机推荐

  1. programming review (c++): (1)vector, linked list, stack, queue, map, string, bit manipulation

    编程题常用知识点的review. most important: 想好(1)详尽步骤(2)边界特例,再开始写代码. I.vector #include <iostream> //0.头文件 ...

  2. MySQL CREATE TRIGGER (1)

    CREATE TRIGGER语法 CREATE TRIGGER trigger_name trigger_time trigger_event    ON tbl_name FOR EACH ROW ...

  3. NDK以及C语言基础语法(二)

    一.字符串类:(属于类类型) -String (在C++中才有) 使用之前必学引入String 类型: 引入String头文件(系统的头文件): #include <string>   p ...

  4. Git 自己的一些工作中的总结

    这个网址很重要:https://gitee.com/progit/2-Git-%E5%9F%BA%E7%A1%80.html#2.4-%E6%92%A4%E6%B6%88%E6%93%8D%E4%BD ...

  5. html学习笔记(2)-字母大小写转换练习

    主要应用了text-transform属性值: uppercase:所有单词的字母都大写: lowercase:所有单词的字母都小写: capitalize:每个单词的首字母都大写: none:默认值 ...

  6. Bloom Filters

    http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html A Bloom filter is a method for represe ...

  7. mysql系列之1.mysql基础

    非关系型(NOSQL)数据库 键值存储数据库: memcached  /  redis  /  memcachedb  /  Berkeley db 列存储数据库: Cassandra  /  Hba ...

  8. pjax + tp5,实现局部无刷新返回数据

    文件1:\application\admin\controller\Setting.php 最后一句代码:要fetch原页面 <?php namespace app\admin\controll ...

  9. 题解 P1387 【最大正方形】

    传送门 搞不清楚为什么这一题要DP . . . . . . 思路: \(n\le100\),考虑暴力. 要求一大块区间内都是1,考虑前缀和. 在矩阵中求一个符合条件的子矩阵,考虑\(n^3\)的&qu ...

  10. 【linux】top更改排序顺序

    top更改排序顺序的方式有很多,这里介绍两个比较简单使用的. 1,快捷键: 大写M:根据内存排序,默认从大到小,大写R更改为从小到大排序 大写P:根据CPU使用排序,默认从大到小,大写R更改为从小到大 ...