Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))
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(后缀数组))的更多相关文章
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
- 【Luogu3804】【模板】后缀自动机(后缀自动机)
[Luogu3804][模板]后缀自动机(后缀自动机) 题面 洛谷 题解 一个串的出现次数等于\(right/endpos\)集合的大小 而这个集合的大小等于所有\(parent\)树上儿子的大小 这 ...
- D. Match & Catch 后缀自动机 || 广义后缀自动机
http://codeforces.com/contest/427/problem/D 题目是找出两个串的最短公共子串,并且在两个串中出现的次数只能是1次. 正解好像是dp啥的,但是用sam可以方便很 ...
- 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数
目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...
- [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp
品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...
- spoj SUBST1 - New Distinct Substrings【SAM||SA】
SAM里的转台不会有重复串,所以答案就是每个right集合所代表的串个数的和 #include<iostream> #include<cstdio> #include<c ...
- Luogu3804 【模板】后缀自动机(后缀自动机)
建出parent树统计即可.开始memcpy处写的是sizeof(son[y]),然后就T掉了……还是少用这种东西吧. 同时也有SA做法.答案子串一定是名次数组中相邻两个串的lcp.单调栈统计其是几个 ...
- luogu SP8093 后缀自动机+树状数组+dfs序
这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $ ...
- BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)
题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...
随机推荐
- Redis (非关系型数据库) 数据类型 之 String类型
Redis 一个内存数据库,通过 Key-Value 键值对的的方式存储数据.由于 Redis 的数据都存储在内存中,所以访问速度非常快,因此 Redis 大量用于缓存系统,存储热点数据,可以极大的提 ...
- kbmmw 5.04 发布
增加了一大波功能,消灭了一大堆问题,也肯定引进了一大票BUG.We are happy to announce the release of our latest version of kbmMW. ...
- 2018.11.06 洛谷P1099 树网的核(最短路+枚举)
传送门 之前看李煜东的书一直感觉是道神题. 然后发现这题数据范围只有300?300?300? 直接上floydfloydfloyd然后暴力就完了啊. 代码: #include<bits/stdc ...
- static关键字的功能
转载:https://blog.csdn.net/guotianqing/article/details/79828100 C语言&C++ 1.局部变量 如果在一个函数内部定义了一个静态变量, ...
- java中的四种修饰符:private、protected、public和default的区别
本类 本包 子类 包外 public 可以 可以 可以 可以 protected 可以 可以 可以 不可以 default 可以 可以 不可以 不可以 private 可以 不可以 不可以 不可以 ...
- centos7,配置nginx服务器
安装准备 首先由于nginx的一些模块依赖一些lib库,所以在安装nginx之前,必须先安装这些lib库,这些依赖库主要有g++.gcc.openssl-devel.pcre-devel和zlib-d ...
- python 基础_ 打印输出 循环分支2
一.在python3中的打印输出 1.输出字符串是print("hello world!!!") #输出字符串的时候可以是单引号括起来,也可以是双引号括起来.区别在于 2.输出变量 ...
- AngularJS封装UEditor
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- SDIBT 2345 (3.2.1 Factorials 阶乘)
Description N的阶乘写作N!表示小于等于N的所有正整数的乘积.阶乘会很快的变大,如13!就必须用32位整数类型来存储,70!即使用浮点数也存不下了.你的任务是找到阶乘最后面的非零位.举个例 ...
- Kindeditor图片粘贴上传(chrome)
kindeditor4.1.x版本已支持图片批量上传,不过传统的选文件上传的方式依然效率低下. 很多时候,编辑人员可能需要将一个文档中图片上传到网上,那么,按照传统的上传方法,他必须先将图片另存为到本 ...