spoj 694 求一个字符串中不同子串的个数
SPOJ Problem Set (classical)694. Distinct SubstringsProblem 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.
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 1011 int 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 求一个字符串中不同子串的个数的更多相关文章
- hdu3068 求一个字符串中最长回文字符串的长度 Manacher算法
最长回文 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- java集合TreeMap应用---求一个字符串中,每一个字母出现的次数
package cn.itcast.p1.map.test; import java.util.Iterator; import java.util.Map; import java.util.Tre ...
- 求一个数组中最小的K个数
方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如 ...
- poj 2406 求字符串中重复子串的个数
Sample Input abcdaaaaababab.Sample Output 1 //1个abcd4 //4个a3 //3个ab #include<stdio.h> #include ...
- 求一个数组中重复数字的个数,要求复杂度为O(n)
给出代码 #include <stdio.h> #include <unistd.h> #include <iostream> #include <memor ...
- 一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数,如有多个重复的则都求出。
主要掌握String中的方法 char[] toCharArray() 将此字符串转换为一个新的字符数组. int indexOf(String str) 返回 ...
- 基于python 3.5 所做的找出来一个字符串中最长不重复子串算法
功能:找出来一个字符串中最长不重复子串 def find_longest_no_repeat_substr(one_str): #定义一个列表用于存储非重复字符子串 res_list=[] #获得字符 ...
- 38 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. public class _038PrintLength { public static void main(Stri ...
- 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度
import java.util.Scanner; /** * [程序38] * * 题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. * * @author Jame ...
随机推荐
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- 【最短路】NOIP模拟赛 虫洞
虫洞 [题目描述] N个虫洞,M条单向跃迁路径.从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间.虫洞有白洞和黑洞之分.设一条跃迁路径两端的虫洞质量差为delta. 1. 从白洞跃迁到 ...
- 【递推】【组合计数】UVA - 11401 - Triangle Counting
http://blog.csdn.net/highacm/article/details/8629173 题目大意:计算从1,2,3,...,n中选出3个不同的整数,使得以它们为边长可以构成三角形的个 ...
- Android手机 "已安装了存在签名冲突的同名数据包"
如果你不是开发者:如果你在android上更新一个已经安装过较早版本软件时,安装到最后一步提示你:已安装了存在签名冲突的同名数据包,然后安装失败.这是因为旧版软件的签名信息与新版不一致造成的.你可以卸 ...
- nginx配置本地https
客户端如何验证服务器的证书呢?服务器自己的证书必须经过某"权威"证书的签名,而这个"权威"证书又可能经过更权威的证书签名,这么一级一级追溯上去,最顶层那个最权威 ...
- React.js学习知识小结(一)
学习React也有半个月了吧,这里对所学的基础知识做个简单的总结.自己先是跟着官方文档学,差不多学了四五天,也跟着入门教程做了一个简单的小栗子.然后跟着阮一峰老师的教程上手了几个小Demo,后来在网上 ...
- 移动应用安全开发指南(Android)--Android组件和IPC
概述 移动应用开发中,往往有跨进程通信的需求,方便地实现程序间的数据共享.Android提供了多种IPC通信的方式,给开发人员带来了便利,但如果选择或使用不当,就有可能发生各种各样的风险. 安全准则 ...
- Jenkins环境初步配置
为研究在kubernetes上的CICD,先在物理环境下安装个JenKins热热身. 安装Jenkins 在官网https://jenkins.io/下载war包,我的是http://mirrors. ...
- Asp.net Core CORS(跨域资源共享)实验
环境:Asp.Net Core 2 1.问题 最近项目在调用远程UI时遇到点麻,在调用远程CSS文件时无法加载其中的字体文件.远程CSS文件对字体的定义: @font-face { font-fami ...
- vim文本编辑工具—修改文件内容
在vim中进行文本替换: 1.替换当前行中的from: :s/from/to/ (其中s是英文单词substitute第一个字母,表示替换的意思) :s/from/to/ == :.s/fr ...