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. centos 开机自启设定:

    在sentos系统下,主要有两种方法设置自己安装的程序开机启动.1.把启动程序的命令添加到/etc/rc.d/rc.local文件中,比如下面的是设置开机启动httpd. #!/bin/sh # # ...

  2. Sony深度学习框架 - Neural Network Console - 教程(1)- 原来深度学习可以如此简单

    “什么情况!?居然不是黑色背景+白色文字的命令行.对,今天要介绍的是一个拥有白嫩的用户界面的深度学习框架.” 人工智能.神经网络.深度学习,这些概念近年已经涌入每个人的生活中,我想很多人早就按捺不住想 ...

  3. TCP协议数据包及攻击分析

    TCP/IP协议栈中一些报文的含义和作用 URG: Urget pointer is valid (紧急指针字段值有效) SYN: 表示建立连接 FIN: 表示关闭连接 ACK: 表示响应 PSH: ...

  4. java内存结构JVM——java内存模型JMM——java对象模型JOM

    JVM内存结构 Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途.其中有些区域随着虚拟机进程的启动而存在,而有些区 ...

  5. 找"1"

    题目:给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的次数. 要求:1.写一个函数f(N),返回1到N之间出现“1”的个数.例如f(12)=5. 2.在32位整数范围内 ...

  6. Oracle Form Builder

    Oracle Form Builder 是Oracle的一个开发工具,可以针对Oracle公司的E-Business Suit的ERP系统开发的.对应的还有reports builder. Oracl ...

  7. 删除一个数字之后数列gcd最大

    ★实验任务 顾名思义,互质序列是满足序列元素的 gcd 为 1 的序列.比如[1,2,3], [4,7,8],都是互质序列.[3,6,9]不是互质序列.现在并不要求你找出一个互质 序列,那样太简单了! ...

  8. ThinkPhp输入参数过滤

    I('id',0); // 获取id参数 自动判断get或者post,不存在时返回默认值0 I('post.name','','htmlspecialchars'); //获取$_POST['name ...

  9. angularJS1笔记-(12)-自定义指令(compile/link)

    index.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  10. React鼠标事件

    说明:假设有一个用户名片,当鼠标滑到上面,显示用户详细信息,且用户详情卡片位置随鼠标位置改变而改变. UI框架:Material-ui 实现思路: 1.一个用户简介组件A(用于展示用户列表): 2.一 ...