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$里跑, ...
随机推荐
- create a plugin for PowerShell ISE
可参考:Creating Add-ons, Plugins, and Tools for the PowerShell ISE http://www.leeholmes.com/blog/2013/0 ...
- PHP字符串替换函数
str_replace函数 描述:实现字符串替换,区分大小写 语法:mixed str_replace(mixed $search, mixed replace, mixed $subject, [i ...
- linux_开启mysql服务
想要连接mysql的时候必须先开启mysql的服务 service mysqld start mysql -u root -p 输入密码
- JSON文件导入Unity3d中是空的的问题
将Json文件的内容在网上在线的Json文件编辑器导出后再导入即可
- php中 isset函数有什么功能
isset是判断一个变量是否定义过即使它没有值,返回值也是true比如$name="";或var $name;那么if(isset($name))echo 1;它也会输出1,因为$ ...
- 使用Ant发布web应用到tomcat
使用Ant发布web应用到tomcat 来自:http://blog.csdn.net/hbcui1984/article/details/1954537 今天在公司用ant写了个部署web应用的脚本 ...
- git安装项目步骤
1.git clone git@gitee(github).com:项目地址.git 2.cd 项目根目录 3.composer install 4.如果需要数据迁移,cmd中到项目根目录 php a ...
- PHP array
一.数组操作的基本函数 数组的键名和值 array_values($arr);获得数组的值 array_keys($arr);获得数组的键名 array_flip($arr);数组中的值与键名互换(如 ...
- java常用设计模式八:代理模式
一.概述 代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象. 其特征是代理类与委托类有同样的接口,真正的核心业务逻辑还是在实际对象里面. 二.为什么要使用代理模式 当 ...
- 解决Linux下IDEA无法使用ibus输入法的问题和tip乱码
一:可以先按网上的配置/etc/profile里的输入法的一些参数,我是先配置了这些参数的,但是输入法还是没用,后来一直没管它了,今天用了一些方式可以了但不敢保证不需要先配置那些参数: 二:情况:开启 ...