不同子串

  题目描述:给定一个有小写英文字母构成的字符串T,求其不同子串个数

  数据范围及限制:一个串,长度不超过100000

  输入样例1:

    ababa

  输出样例1:

    9

  输入样例2

    ebvylfeicorjhpovljmgqawckptcqfuynhvnqwokvowxjgvjhztxmgzwkgvuvhsilrslnzcvmconbabwrpfniknqsimyutwstzzc

  输出样例2:

    4968

  输入样例3:

    riokzisztaydqovqjcdnojfykqjfstevddxtxbtwgzlmwqnhijuemkxaaqmjqscdpnzgseezaexluxdmdkoijafpecganbycwsjs

  输出样例3: 

    4999757677

  题解:

    因为每个子串都是某个后缀的前缀,所以想到用后缀数组,首先要知道后缀数组中height[i]的含义,height[i]不仅指排名第i的和排名第i-1的(后缀)的最长相同前缀,还指排名第i的和排名1~i-1的最长相同前缀,可以举几个例子试试。

    知道了这个性质,那么每一个后缀中只能由它得到的前缀的个数就是n-sa[i]-height[i],n-sa[i]得到这个后缀的长度(我是从0开始的),height[i]个前缀在排名1~i-1的后缀中已经得到,所以要减去,不计入答案。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long LL;
10 const LL maxn=200000;
11 LL r[maxn],sa[maxn],wa[maxn],wb[maxn],wv[maxn],Ws[maxn];
12 LL cmp(LL *r,LL a,LL b,LL l){
13     return r[a]==r[b]&&r[a+l]==r[b+l];
14 }
15 void da(LL *r,LL *sa,LL n,LL m){
16     LL i,j,p,*x=wa,*y=wb,*t;
17     for(i=0;i<m;i++) Ws[i]=0;
18     for(i=0;i<n;i++) Ws[x[i]=r[i]]++;
19     for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
20     for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i;
21
22     for(j=1,p=1;p<n;j*=2,m=p){
23         for(p=0,i=n-j;i<n;i++) y[p++]=i;
24         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
25
26         for(i=0;i<n;i++) wv[i]=x[y[i]];
27         for(i=0;i<m;i++) Ws[i]=0;
28         for(i=0;i<n;i++) Ws[wv[i]]++;
29         for(i=0;i<m;i++) Ws[i]+=Ws[i-1];
30         for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];
31
32         for(t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1;i<n;i++)
33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
34     }
35 }
36 LL rank[maxn],height[maxn];
37 void calheight(LL *r,LL *sa,LL n){
38     LL i,j,k=0;
39     for(i=0;i<n;i++) rank[sa[i]]=i;
40     for(i=0;i<n;height[rank[i++]]=k)
41         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
42     return ;
43 }
44 char s[maxn];
45 LL num[maxn],len,ans;
46 int main(){
47     freopen("distinct.in","r",stdin);
48     freopen("distinct.out","w",stdout);
49     scanf("%s",s); len=strlen(s);
50     for(LL i=0;i<len;i++) num[i]=s[i]-‘a‘+2;
51     da(num,sa,len,30);
52     calheight(num,sa,len); height[0]=0;
53     for(LL i=0;i<len;i++){
54         LL k=len-sa[i];
55         ans+=k-height[i];
56     }
57     printf("%lld",ans);
58     return 0;
59 }
时间: 2024-09-29 15:29:24

不同子串的相关文章

LeetCode 30 Substring with Concatenation of All Words(与所有文字串联子串)(*)

翻译 给定一个字符串S,一个单词的列表words,全是相同的长度. 找到的子串(多个)以s即每个词的字串联恰好一次并没有任何插入的字符所有的起始索引. 原文 You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word

最长公共子串

(连续) - 阿里笔试[分析+编码] 题目描述:给定一个query和一个text,均由小写字母组成.要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度.例如,query为“acbac”,text为“acaccbabb”,那么text中的“cba”为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3.请注意程序效率. [思路]用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0.然后求出对角线最长的1序列,其对应的位置

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

Problem Description Now you are back,and have a task to do: Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s. And you have some query,each time you should calculate f(s[l...r]), s[l

c之PAT刷题---删除字符串中的特定子串

改了好久还是没有全过,等明天再看吧!好好休息,明天继续. #include<stdio.h> #include<string.h> char *delete(char str1[80],char str2[80]){ int len1,len2,l;//l记录出现字符相同的起始位置 len1=strlen(str1); len2=strlen(str2); for(int i=0;str1[i]!='\0';i++){ if(str1[i]==str2[0]){ l=i;//记下相

寻找最大子串

题目:从一个数组中寻找一个连续子数组,使其中元素之和最大,给出该和值. 例如:数组[-2, 1, -3, 4, -1, 2, 1, -5, 4]和最大的子串是[4, -1, 2, 1],其和为6. 分析: 将数组从中间切分,中间元素属于左边,则最大子串为下面三种情况之一: 子串仅包含左边元素: 子串仅包含右边元素: 子串同时包含左边和右边的元素: 代码: // JavaScript solution function findMaxSubArray(a, begin, end) {   if(b

获取两个字符串中最大相同子串

2.获取两个字符串中最大相同子串.第一个动作:将短的那个串进行长度一次递减的子串打印. "cvhellobnmtanop" "andefc" 思路: 1,将短的那个子串按照长度递减的方式获取到. 2,将每获取到的子串去长串中判断是否包含,如果包含,已经找到! package tan; class Test { public static String getMaxSubString(String s1,String s2) { String max = "

字符串问题之 最小包含子串长度

str1 和 str2  求str1 的子串 中含有str2 的所有字符的最小字串长度 例如: str1 ="abcde" str2="ac"    返回3 本题适合用还款方法  str1 去还 str2 里面的元素 package TT; public class Test7 { public static int minLength(String str1, String str2){ if(str1 == null || str2 == null || str

SPOJ 694 不同子串个数

一个论文题,求一个字符串有多少个不同的子串. 每个字符串可以看做一个后缀的前缀,然后,就转换为求每一个后缀中,不同的子串有多少. 每一个后缀,根据长度,可以提供len - sa[i] 个子串,但是,画图可以看出,有一些是重复的,height[i]. #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int maxn = 1000+5; char str[max

【NOIP2015】子串

题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之间用一个空格隔

NOI2015子串

题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之间用一个空格隔