spoj 694 求一个字符串中不同子串的个数
来源:互联网 发布:php爬虫框架 编辑:程序博客网 时间:2024/05/16 19:34
SPOJ Problem Set (classical)
694. Distinct Substrings
Problem code: DISUBSTR
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. (转自:http://www.tuicool.com/articles/nMvEFvJ)
1、用前缀开看不同子串:可以看出-- 长度为i的字符串一共有i个前缀
2、每一个子串都是某个后缀的前缀,于是问题 等价于求所有不同的前缀的个数
然后按sa[1],sa[2]...逐次加入后缀观察: suffix(sa[i])长度为n-sa[i],一共有n-sa[i]个前缀,减去lcp[i-1](就是与前一个后缀的最长公共前缀的长度),就是新加入的新的前缀的个数
最后求和即可
注意我的lcp[i]指的是suffix(sa[i])和suffix(sa[i+1])的公共前缀的长度
#include <cstdio>#include <iostream>#include <string>#include <algorithm>#include <cmath>#include <cstring>using namespace std;#define MAXN 1011int n,k;//n=strlen(s);int Rank[MAXN];int tmp[MAXN];char s[MAXN];int lcp[MAXN],sa[MAXN];/*使用Rank对sa排序*/bool cmpSa(int i, int j){ if(Rank[i] != Rank[j])return Rank[i] < Rank[j]; else { /*下面的Rank[t],已经是以t开头长度小于等于k/2的, sa[i]的名次,只是以i开头的后缀,而长度不同*/ int ri = i+k <=n? Rank[i+k]:-1; int rj = j+k <= n ? Rank[j+k]:-1; return ri <rj; }}/*计算SA*/void consa(){ /*n=strlen(s); 必要时注明*/ /*初始化sa和rank保证两点 1、Rank[i]表示下标为i的是第几大,必须表示出相对大小,可以直接用字符代表其大小 2、sa[1...n]值为1..n*/ for(int i=0;i<=n;i++){ sa[i]=i;Rank[i] = i < n?s[i]:-1; } /*利用长度为k的字符串对长度为2*k的字符串排序*/ for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1开始,因为0*2=0*/ { sort(sa,sa+n+1,cmpSa); tmp[sa[0]] = 0; /*此时tmp只是暂存rank*/ for(int i=1;i<=n;i++){ tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0); /*这一句很关键,等号右侧的sa[i]在此循环里表示第i大的长度小于等于k/2的字符串, 从而求出第i大的长度小于等于k的字符串的sa[i]*/ } for(int i=0;i<=n;i++){ Rank[i] = tmp[i]; } }}void construct_lcp(){ //n=strlen(s); for(int i=0; i<=n; i++)Rank[sa[i]]=i; int h=0; lcp[0]=0; for(int i=0;i<n;i++) { int j=sa[Rank[i]-1]; if(h>0)h--; for(; j+h<n && i+h<n; h++) { if(s[j+h]!=s[i+h])break; } lcp[Rank[i]-1]=h; }}int main(){ int t,ans; scanf("%d",&t); while(t--) { ans=0; scanf("%s",s); n=strlen(s); consa(); construct_lcp(); for(int i=1;i<=n;i++) { ans+=n-sa[i]-lcp[i-1]; } printf("%d\n",ans); } return 0; return 0;}
- spoj 694 求一个字符串中不同子串的个数
- spoj 694 求一个字符串中不同子串的个数
- spoj 694 求一个字符串中不相同子串的个数
- SPOJ-694-求字符串中不同子串个数(后缀数组)
- spoj 694 求不同子串的个数
- spoj 694 Distinct Substrings(求不同的子串个数,后缀数组基础题)
- SPOJ 题目694 Distinct Substrings(后缀数组,求不同的子串个数)
- hdu 4416 后缀自动机 求一个字符串中出现的不同子串的个数(去除一些其他字符串的子串)
- spoj 405 求不同子串的个数 后缀数组和高度数组的应用
- SPOJ 题目705 New Distinct Substrings(后缀数组,求不同的子串个数)
- 求一个字符串中某个子串的个数(C++)
- 求无符号数二进制中1的个数&&求一个字符串中最长的连续子串
- SPOJ 694、705 后缀数组:求不同子串
- SPOJ 694 求一个字符串有多少子串 后缀数组
- 求字符串的子串个数
- 求一个字符串中大写字母的个数
- 查找字符串中一个子串的个数
- 计算一个字符串中包含子串的个数
- boost并发编程(三)——共享互斥量
- 我的getElementsByClassName实现
- android手机坐标系,原来我一直都没理解透
- SendMessage与PostMessage的区别
- VB.net学习笔记(十四) 反射、多态
- spoj 694 求一个字符串中不同子串的个数
- 《2》Maven项目工程创建
- Ubuntu 14.04可以ping通DNS 无法访问外网的解决办法
- 【Unity快速实现小功能】实现摄像机跟随角色移动功能
- gdcpc2015A题
- 放过你与口语
- C#中,变量前的@符号
- 重复提交、重复刷新、防止后退的问题以及处理方式分析
- 大整数的加减乘运算