【spoj8222】 Substrings
http://www.spoj.com/problems/NSUBSTR/ (题目链接)
题意
给出一个字符串S,令${F(x)}$表示S的所有长度为x的子串出现次数的最大值。求${F(1)......F(length(S))}$
Solution
后缀自动机例题,下面写几点自己认为理解后缀自动机的重点。
- 后缀自动机相对于后缀树就是将Right集合相同的子串合用一个节点来表示。每一个节点代表一个状态S,这个状态可能包含很多长度区间连续的子串,这些子串的右端点固定,它们的Right集合相同。
- 往上跳parent的过程相当于将子串的前面一节截掉,得到一个长度更短的子串,它们的Right集合变多了。走状态转移边的过程相当于在子串的后面添加新的字符,到达新的状态。
- 构造过程中,情况一很好理解,考虑情况二和情况三的区别。情况二是parent中存在x边到达某一个状态${V_q}$,并且这个状态的所有子串都可以接受当前插入的这个这个后缀。情况三是虽然存在状态${V_q}$,但是这个状态所包含一部分长度比较长的的子串无法接受要插入的这个后缀,所以将它拆成两份,一份可以接受,一份不能接受。
对于这道题,我们需要做的就是计算SAM中每个节点的Right集合的大小,即在串中的出现次数。因为parent树的某个节点Right集合是它父亲的真子集,所以我们考虑从parent树的底端向上不断更新祖先的Right集合。
代码模着hzwer写的,加了点注释。这里对Max的排序用了基数排序,看着好不爽,但是nlogn的算法就TLE了→_→。
看了DaD3zZ的程序大有所感,update一下。
代码
// spoj8222
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=250010;
int n;
int f[maxn];
char s[maxn]; namespace SAM {
int last,Dargen,sz;
int ch[maxn<<1][26],id[maxn<<1],len[maxn<<1],par[maxn<<1],r[maxn<<1],b[maxn];
void Extend(int c) {
int np=++sz,p=last;last=np; //p是上次插入的节点,np为现在正在插入的这个节点,last变成了np
len[np]=len[p]+1; //Max(s),也就是到达这个节点的最长的子串(相当于x的前缀的长度→_→)
for (;p && !ch[p][c];p=par[p]) ch[p][c]=np; //p以及其在parent树上的祖先没有c边的全部连边(可以从right集合的角度去考虑)
if (!p) par[np]=Dargen; //如果都没有c边,则np的parent为Dargen————情况1
else {
int q=ch[p][c]; //找到了深度最深的有c边的祖先
if (len[q]==len[p]+1) par[np]=q; //情况2
else { //情况3
int nq=++sz;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
par[nq]=par[q];
par[np]=par[q]=nq;
for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
}
}
}
void build() {
last=Dargen=sz=1;
for (int i=1;i<=n;i++) Extend(s[i]-'a');
}
void pre() {
for (int p=Dargen,i=1;i<=n;i++) p=ch[p][s[i]-'a'],r[p]++; //先将主链上的right全部加1
for (int i=1;i<=sz;i++) b[len[i]]++; //按照len[x]从小到大基数排序,相当于对SAM图进行拓扑排序
for (int i=1;i<=n;i++) b[i]+=b[i-1];
for (int i=1;i<=sz;i++) id[b[len[i]]--]=i;
for (int i=sz;i>=1;i--) r[par[id[i]]]+=r[id[i]]; //从后往前for,自底向上更新parent的right大小
}
void solve() {
for (int i=1;i<=sz;i++) f[len[i]]=max(f[len[i]],r[i]); //更新答案
for (int i=n;i>=1;i--) f[i]=max(f[i],f[i+1]);
}
}
using namespace SAM; int main() {
scanf("%s",s+1);
n=strlen(s+1);
build();
pre();
solve();
for (int i=1;i<=n;i++) printf("%d\n",f[i]);
return 0;
}
【spoj8222】 Substrings的更多相关文章
- 【spoj8222】Substrings
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- 【SPOJ8222】Substrings (后缀自动机)
题意: 给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值. 求F(1)..F(Length(S)) Length(S) <= 250000 思路:板子中st[x]定义为r ...
- 【SPOJ】Substrings(后缀自动机)
[SPOJ]Substrings(后缀自动机) 题面 Vjudge 题意:给定一个长度为\(len\)的串,求出长度为1~len的子串中,出现最多的出现了多少次 题解 出现次数很好处理,就是\(rig ...
- 【SPOJ】Substrings
出现次数很好处理,就是 \(right/endpos\) 集合的大小 那么,直接构建 \(SAM\) 求出每个位置的\(right\)集合大小 直接更新每个节点的\(longest\)就行了 最后短的 ...
- 【POJ1226】Substrings(后缀数组,二分)
题意: n<=10,len<=100 思路: 只有一个字符串的时候特判一下 #include<cstdio> #include<cstring> #include& ...
- 【UVA10829】 L-Gap Substrings (后缀数组)
Description If a string is in the form UVU, where U is not empty, and V has exactly L characters, we ...
- 【POJ3415】 Common Substrings(后缀数组|SAM)
Common Substrings Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤ ...
- 【SPOJ】Distinct Substrings(后缀自动机)
[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/e ...
- 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)
[SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...
随机推荐
- 【转】HBase技术介绍 转载自 http://www.searchtb.com/2011/01/understanding-hbase.html
HBase简介 HBase – Hadoop Database,是一个高可靠性.高性能.面向列.可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群. HB ...
- ubuntu 下重装mysql若干问题
最近由于种种原因需要重装mysql.打开终端开始卸载 sudo apt-get remove mysql-comm sudo apt-get auto remove 重新开始安装mysql sudo ...
- 使用ADO对象添加、修改、删除数据
使用ADO对象对数据库中的数据进行添加.修改和删除等操作.首先创建一个ADO类,通过ADO类连接数据库,并打开记录集.例如,使用ADO对象添加.修改.删除数据,程序设计步骤如下:(1)创建一个基于对话 ...
- java下发电子邮件demo
在实际项目中会遇到需要使用邮件注册,或者是使用邮件找回密码等操作,需要使用到邮件发送功能. 其实邮件的发送主要是依赖于邮件协议,只要能实现邮件协议,那么发送邮件其实还是很容易的.这一步java类库已经 ...
- 在web项目中使用cxf开发webservice,包含spring支持
本文主要介绍了,如何使用cxf内置的例子,学会开发webserivce,在web项目中使用,且包含spring支持. webserivce的开发可以使用cxf或者axis,好像还有httpclient ...
- mac编译PHP报错 configure: error: Please reinstall the libcurl distribution - easy.h should be in <curl-dir>/include/curl/
解决办法 brew install curl xcode-select --install
- 转 如何使用V7包中ActionBar(Eclipse版)
http://blog.csdn.net/appte/article/details/11712591 以前3.0以前的版本要使用ActionBar,必须使用国外大牛写的ActionBarSherlo ...
- postgres 错误duplicate key value violates unique constraint 解决方案
SELECT setval('tablename_id_seq', (SELECT MAX(id) FROM tablename)+1) 主要是:serial key其实是由sequence实现的,当 ...
- URL 传+号到后台变空格问题解决方案
今天巧合遇到这个问题,下面是网上找的解决方案. 原文:http://blog.sina.com.cn/s/blog_a0949eec01010xta.html 今天在调试客户端向服务器传递参数时,参数 ...
- 常用Select语句
--语 句 功 能--数据操作SELECT --从数据库表中检索数据行和列INSERT --向数据库表添加新数据行DE ...