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;
}

【spoj NSUBSTR】 Substrings的更多相关文章

  1. 【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

    题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为l ...

  2. 【SPOJ 8222】Substrings

    http://www.spoj.com/problems/NSUBSTR/ clj课件里的例题 用结构体+指针写完模板后发现要访问所有的节点,改成数组会更方便些..于是改成了数组... 这道题重点是求 ...

  3. 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)

    54  种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...

  4. 【SPOJ 694】Distinct Substrings (更直接的求法)

    [链接]h在这里写链接 [题意] 接上一篇文章 [题解] 一个字符串所有不同的子串的个数=∑(len-sa[i]-height[i]) [错的次数] 0 [反思] 在这了写反思 [代码] #inclu ...

  5. 【SPOJ 694】Distinct Substrings

    [链接]h在这里写链接 [题意]     给你一个长度最多为1000的字符串     让你求出一个数x,这个x=这个字符串的不同子串个数; [题解]     后缀数组题.     把原串复制一份,加在 ...

  6. 【spoj SUBST1】 New Distinct Substrings

    http://www.spoj.com/problems/SUBST1/ (题目链接) 题意 求字符串的不相同的子串个数 Solution 后缀数组论文题. 每个子串一定是某个后缀的前缀,那么原问题等 ...

  7. 【SPOJ – SUBST1】New Distinct Substrings 后缀数组

    New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...

  8. 【SPOJ 694】Distinct Substrings 不相同的子串的个数

    不会FQ啊,没法评测啊,先存一下代码QAQ 2016-06-16神犇Menci帮我测过AC了,谢谢神犇Menci QwQ #include<cstdio> #include<cstr ...

  9. 【SPOJ 2319】 BIGSEQ - Sequence (数位DP+高精度)

    BIGSEQ - Sequence You are given the sequence of all K-digit binary numbers: 0, 1,..., 2K-1. You need ...

随机推荐

  1. 基于python的scrapy框架爬取豆瓣电影及其可视化

    1.Scrapy框架介绍 主要介绍,spiders,engine,scheduler,downloader,Item pipeline scrapy常见命令如下: 对应在scrapy文件中有,自己增加 ...

  2. GIT问题(一)——push冲突

  3. JavaWeb-Servlet-Tomcat

    Servlet就是运行在服务器上的Java类.Servlet容器为javaweb应用提供运行时环境,负责管理Servlet和JSP的生命周期,以及管理它们的共享数据. Servlet容器软件——Tom ...

  4. 15 Puzzle (4乘4谜题) IDA*(DFS策略与曼哈顿距离启发) 的C语言实现

    大家好!这是我的第一篇博客,由于之前没有撰写博客的经验,并且也是初入计算机和人工智能领域,可能有些表述或者理解不当,还请大家多多指教. 一.撰写目的 由于这个学期在上算法与数据结构课程的时候,其中一个 ...

  5. Mongodb For Mac OSX && 登录验证

    题外话:尽管有不少人贴出了 <我不用mongodb的十大理由> 等系列文章,但是 NoSQL 的发展不会因此而止步, mongodb 是 NoSQL 的典型代表,楼主还是抱乐观态度的,有人 ...

  6. JS进阶系列之原型、原型链

    最近在看 JavaScript忍者秘籍 这本书的时候,再加上最近遇到的关于原型.原型链的面试题,所以萌生了要把这些知识梳理一遍的想法,所以以下是我自己对原型.原型链的看法 什么是原型 提到原型,我们可 ...

  7. C++自学及C的补缺

    我这个寒假可以坐在电脑前的时间算是比较少的,因为我放假不久后就去打工了,而打工的时间是很流动的,所以我无法固定时间来学习,因此我只能根据我的打工时间来安排我的学习. 由于我的书是除夕前夕淘宝的,近期是 ...

  8. HTML和CSS <h1> --1-- <h1>

    Html和CSS的关系 学习web前端开发基础技术需要掌握:HTML.CSS.JavaScript语言.下面我们就来了解下这三门技术都是用来实现什么的: 1. HTML是网页内容的载体.内容就是网页制 ...

  9. 团队作业5-Alpha版本测试报告(彼岸芳华队)

    请根据团队项目中软件的需求文档.功能说明.系统设计和测试计划,写出软件的测试过程和测试结果,并回答下述问题. 一.在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个?(10分) 在测试过程 ...

  10. 电脑CPU开机上电后的第一条指令

    结合上面的文章,CPU上电后第一条指令是通过CS:IP来指定的,CPU厂家会给其初始值,对于386处理器来说,CPU第一条指令地址是 0xFFFFFFF0 这里会有一个问题,CPU怎么能一上来就去0x ...