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.

Sample Input

2
CCCCC
ABABA

Sample Output

5
9

题意:

给出\(n\)个串,求每个串中本质不同的子串

题解:

一、后缀自动机

把串前一个后缀自动机,然后在每次加入字符的时候把答案加上当前长度和他\(parent\)的点的长度的差。这里利用了后缀自动机的一个性质:

  • 每个点后面的本质不同的串的个数等于这个点的长度减去他的\(parent\)的长度。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
char s[N];
int a[N],c[N],as;
struct SAM{
int last,cnt;
int size[N],ch[N][52],fa[N<<1],l[N<<1];
void ins(int c){
int p=last,np=++cnt;last=np;l[np]=l[p]+1;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[p]+1==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
as+=l[np]-l[fa[np]];
}
void build(char s[]){
memset(ch,0,sizeof ch);
memset(l,0,sizeof l);
memset(fa,0,sizeof fa);
memset(size,0,sizeof size);
int len=strlen(s+1);
last=cnt=1;
for(int i=1;i<=len;++i){
if('A'<=s[i]&&s[i]<='Z')ins(s[i]-'A');
else ins(s[i]-'a'+26);
}
}
}sam;
int main(){
int n;
cin>>n;
while(n--){
as=0;
scanf("%s",s+1);
sam.build(s);
printf("%d\n",as);
}
}

二、后缀数组

处理出sa和height,以公式 当前后缀的贡献%c[i]=n-sa[i]+1-height[i]$计算出结果就行了。

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
char s[N];
int n;
int fir[N],sec[N],rnk[N],t[N],sa[N],b[N];
void sort(){
memset(t,0,sizeof t);
for(int i=1;i<=n;++i)t[sec[i]]++;
for(int i=1;i<N;++i)t[i]+=t[i-1];
for(int i=n;i;--i)b[t[sec[i]]--]=i;
memset(t,0,sizeof t);
for(int i=1;i<=n;++i)t[fir[b[i]]]++;
for(int i=1;i<N;++i)t[i]+=t[i-1];
for(int i=n;i;--i)sa[t[fir[b[i]]]--]=b[i];
}
int height[N];
void get_height(char *s){
int k=0;
for(int i=1;i<=n;++i){
if(rnk[i]==1){
height[i]=0;
continue;
}
if(k)--k;
int j=sa[rnk[i]-1];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
height[i]=k;
}
}
void get_sa(char *s){
for(int i=1;i<=n;++i)rnk[i]=s[i];
for(int k=1;k<=n;k*=2){
for(int i=1;i<=n;++i){
fir[i]=rnk[i];
if(i+k>n)sec[i]=0;
else sec[i]=rnk[i+k];
}
sort();
int num=1;rnk[sa[1]]=1;
for(int i=2;i<=n;++i){
if(fir[sa[i]]!=fir[sa[i-1]]||sec[sa[i]]!=sec[sa[i-1]])num++;
rnk[sa[i]]=num;
}
if(num==n)break;
}
}
int main(){
int t;
cin>>t;
while(t--){
scanf("%s",s+1);
n=strlen(s+1);
get_sa(s);
get_height(s);
long long ans=0;
for(int i=1;i<=n;++i){
ans+=n-sa[i]-height[i]+1;
}
printf("%lld\n",ans);
}
}

Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))的更多相关文章

  1. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  2. 【Luogu3804】【模板】后缀自动机(后缀自动机)

    [Luogu3804][模板]后缀自动机(后缀自动机) 题面 洛谷 题解 一个串的出现次数等于\(right/endpos\)集合的大小 而这个集合的大小等于所有\(parent\)树上儿子的大小 这 ...

  3. D. Match & Catch 后缀自动机 || 广义后缀自动机

    http://codeforces.com/contest/427/problem/D 题目是找出两个串的最短公共子串,并且在两个串中出现的次数只能是1次. 正解好像是dp啥的,但是用sam可以方便很 ...

  4. 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数

    目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...

  5. [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp

    品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...

  6. spoj SUBST1 - New Distinct Substrings【SAM||SA】

    SAM里的转台不会有重复串,所以答案就是每个right集合所代表的串个数的和 #include<iostream> #include<cstdio> #include<c ...

  7. Luogu3804 【模板】后缀自动机(后缀自动机)

    建出parent树统计即可.开始memcpy处写的是sizeof(son[y]),然后就T掉了……还是少用这种东西吧. 同时也有SA做法.答案子串一定是名次数组中相邻两个串的lcp.单调栈统计其是几个 ...

  8. luogu SP8093 后缀自动机+树状数组+dfs序

    这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $ ...

  9. BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)

    题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...

随机推荐

  1. 【搜索】Shuffle'm Up

    运用第i个s12和第i+1个s12中,每个位置具有的确定的映射关系: pos = pos * 2 + 1 (pos < c) pos = pos * 2 - c * 2 (pos >= c ...

  2. New users can not log on Win8

    方案: http://www.eightforums.com/tutorials/38838-user-profile-service-failed-sign-fix-windows-8-a.html ...

  3. Android音频系统之AudioFlinger(三)

    http://blog.csdn.net/xuesen_lin/article/details/8805091 1.1.1 PlaybackThread的循环主体 当一个PlaybackThread进 ...

  4. web前端面试题库

    web前端面试题及答案   1.常用那几种浏览器测试?有哪些内核(Layout Engine)? 答: (Q1) 浏览器:IE,Chrome,FireFox,Safari,Opera.    (Q2) ...

  5. KAFKA 监控管理界面 KAFKA EAGLE 安装

    概述 Kafka Eagle监控系统是一款用来监控Kafka集群的工具,目前更新的版本是v1.2.3,支持管理多个Kafka集群.管理Kafka主题(包含查看.删除.创建等).消费者组合消费者实例监控 ...

  6. Architecture

    SMART Crossbar The SMART crossbar is the primary building block in a SMART NoC that enables straight ...

  7. Latex表格插入

    \begin{table}[h] \centering \caption{Traffic flows description} \begin{tabular}{|c||c|c|c|c|} \hline ...

  8. java Concurrent包学习笔记(三):ReentrantLock

    一.可重入性的理解 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大.两者都是同一个线程每进入一次,锁 ...

  9. 第04章:MongoDB基本概念

    ① 数据库 MongoDB的一个实例可以拥有一个或多个相互独立的数据库,每个数据库都有自己的集合   集合 集合可以看作是拥有动态模式的表   文档 文档是MongoDB中基本的数据单元,类似于RDB ...

  10. Struts2--HelloWord

    Struts2官网 官网指南 官网下载Struts2.5-min-lib.zip解压把lib目录下jar包拷贝到web项目lib目录下 配置web.xml文件 <filter> <f ...