[spoj694&spoj705]New Distinct Substrings(后缀数组)

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

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

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)。

 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=200005;
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=0;i<m;i++) wc[i]=0;
16     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
17     for(i=1;i<m;i++) wc[i]+=wc[i-1];
18     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
19     for(j=1,p=1;p<n;j*=2,m=p){
20         for(p=0,i=n-j;i<n;i++) y[p++]=i;
21         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
22         for(i=0;i<n;i++) wv[i]=x[y[i]];
23         for(i=0;i<m;i++) wc[i]=0;
24         for(i=0;i<n;i++) wc[wv[i]]++;
25         for(i=1;i<m;i++) wc[i]+=wc[i-1];
26         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
27         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1: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=0;
34     for(i=1;i<=n;i++) rank1[sa[i]]=i;
35     for(i=0;i<n;height[rank1[i++]]=k)
36         for(k?k--:0,j=sa[rank1[i]-1];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(0);
44     cin>>t;
45     while(t--){
46         string s;
47         cin>>s;
48         for(int i=0;i<s.size();i++) r[i]=(int)s[i];
49         r[s.size()]=0;
50         n=s.size();
51         make_sa(r,sa,n+1,129);
52         make_height(r,sa,n);
53         ll sum=s.size()*(s.size()+1)/2;
54         for(int i=2;i<=n;i++){
55             sum-=height[i];
56         }
57         cout<<sum<<"\n";
58     }
59     return 0;
60 }
时间: 2024-10-06 18:11:42

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

SPOJ694&amp;&amp;SPOJ705:Distinct Substrings(后缀数组)

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 one string, whose length is <= 1000 Output For each test case output one number saying the numb

SPOJ694--- DISUBSTR - 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 distin

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 Distinct Substrings 后缀数组

给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和AB height[i]=1; 表明一个长度公共,所以ABA中多出现了A这个子串,所以6-1=5: 对于ABA BA height[i]=0,所以不需要减去. 最后答案为5: #include<iostream> #include<stdio.h> #include<string

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

题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀中找出不同的并计数呢?思路就是所有的可能子串数 - 重复的子串数.首先我们容易得到一个长度为 len 的串的子串数为 len * ( len + 1) / 2.那如何知道重复的子串数呢?答案就是利用后缀数组去跑一遍 Height ,得到所有的最长公共前缀(LCP),这些最长公共前缀的值都存在了 He

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

POJ 1226 Substrings (后缀数组)

题目大意: 问的是m个字符串里,都出现过的子串.子串也可以出现在这个串的逆序串中. 思路分析: 居然wa在全5个 "a" 的数据上. 二分的时候下界不能为0.. 思路大致上是把原串和逆序串全部处理出来,放入str中,然后在每个串中间加一个没有出现过的. 此处注意输入不仅仅是字母. 然后跑一遍后缀数组. 然后用标记计数就好了. #include <iostream> #include <cstdio> #include <algorithm> #inc

hdu 4029 Distinct Sub-matrix (后缀数组)

题目大意: n*m的矩阵中,有多少个子矩阵不是同的. 思路分析: 假设这题题目只是一维的求一个串中有多少个子串是不同的. 那么也就是直接扫描height,然后减去前缀. 现在变成二维,如何降低维度. 知道hash 的作用就是将一个串映射到一个数字. 那我们就将这个矩阵hash,考虑到不同的长度和宽度都会导致不同, 所以就要枚举子矩阵的宽度. hash [i][j] 就表示在当前宽度W 下,从 第 i 行 第 j 个开始往后W长度的串的hash值. 然后将列上相同起点的hash值 子串. 然后将所

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam