【spoj NSUBSTR】 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;
}
【spoj NSUBSTR】 Substrings的更多相关文章
- 【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】
题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为l ...
- 【SPOJ 8222】Substrings
http://www.spoj.com/problems/NSUBSTR/ clj课件里的例题 用结构体+指针写完模板后发现要访问所有的节点,改成数组会更方便些..于是改成了数组... 这道题重点是求 ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
- 【SPOJ 694】Distinct Substrings (更直接的求法)
[链接]h在这里写链接 [题意] 接上一篇文章 [题解] 一个字符串所有不同的子串的个数=∑(len-sa[i]-height[i]) [错的次数] 0 [反思] 在这了写反思 [代码] #inclu ...
- 【SPOJ 694】Distinct Substrings
[链接]h在这里写链接 [题意] 给你一个长度最多为1000的字符串 让你求出一个数x,这个x=这个字符串的不同子串个数; [题解] 后缀数组题. 把原串复制一份,加在 ...
- 【spoj SUBST1】 New Distinct Substrings
http://www.spoj.com/problems/SUBST1/ (题目链接) 题意 求字符串的不相同的子串个数 Solution 后缀数组论文题. 每个子串一定是某个后缀的前缀,那么原问题等 ...
- 【SPOJ – SUBST1】New Distinct Substrings 后缀数组
New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...
- 【SPOJ 694】Distinct Substrings 不相同的子串的个数
不会FQ啊,没法评测啊,先存一下代码QAQ 2016-06-16神犇Menci帮我测过AC了,谢谢神犇Menci QwQ #include<cstdio> #include<cstr ...
- 【SPOJ 2319】 BIGSEQ - Sequence (数位DP+高精度)
BIGSEQ - Sequence You are given the sequence of all K-digit binary numbers: 0, 1,..., 2K-1. You need ...
随机推荐
- GitHub笔记(三)——分支管理和多人协作
三.分支管理 0 语句: 查看分支:git branch 创建分支:git branch <name> 切换分支:git checkout <name> 创建+切换分支:git ...
- Table 组件构建过程中遇到的问题与解决思路
在 GearCase 开源项目构建 Table 组件的过程中.遇到了各式各样的问题,最后尝试了各种方法去解决这些问题. 遇到的部分问题 checkbox 的全选和半选问题 table 组件的排序请求方 ...
- nodejs 中jead模板改为ejs
var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set(' ...
- Daily Scrum 1 --团队项目所需时间估计以及任务分配
考虑到所有的任务不可能逐一细化分配给成员,我们将需要完成的任务进行了大致的分配.任务所需要的具体实现可以参看<学霸网站NABC> 所需要的总时间一共为44h. 我们会在以后的每日任务中进行 ...
- 安装AndroidJDK的坑
最近公司要用weex了,先开始搭一下环境,真的都是坑,写下来大家引以为鉴,我踩坑三天的后果. 首先要安装JavaJDK这个过程就不写了都是程序员网上搜索一下很多,注意找论坛上最新的帖子来看,这里有一个 ...
- 增加ubuntu的内存——设置Swap增加内存
1.查看一下当前Swap分区的状态: $cat /proc/meminfo SwapTotal: 0 kB SwapFree: 0 kB 如果上面二项目都为0,说明没有Swap分区:如果不为0,则说明 ...
- POJ 1239 Increasing Sequences 动态规划
题目链接: http://poj.org/problem?id=1239 Increasing Sequences Time Limit: 1000MSMemory Limit: 10000K 问题描 ...
- windows下的C++ socket服务器(4)
void handleAccept(int socket_fd) { ] = { '\0' }; string cmd; string filename; recv(socket_fd, buf, ) ...
- php 把数字转化为大写中文
PHP 数字转大写中文 PHP入门小菜鸟一枚.下午要求写一个把数字转成大写中文的脚本,百度了一波,几十个博客和网站都是用的那四个代码,第一个运行不了,第二个有问题,不合要求,第三个第四个太长,懒得看, ...
- Alpha版本冲刺(二)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:丹丹 组员7:家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组内 ...