【BZOJ-3998】弦论 后缀自动机
3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 2018 Solved: 662
[Submit][Status][Discuss]
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
0 3
Sample Output
HINT
N<=5*10^5
Source
Solution
后缀自动机的裸题?不过给我挺大帮助的。
建出后缀自动机求K大的问题,先拓扑排序/基数排序,然后递推出每个节点能到的子串数,然后dfs一遍加加减减。
这个题在递推的时候讨论一下即可,T=0时说明每个状态代表一个子串(除空串以外),T=1时每个节点的Parent树的子树中的节点数都是可以得到的子串数,所以需要累加。
而这个累加的过程,可以理解成是求出$Right$集合的大小,所以构建时的新建节点显然不能重复计算。
然后dfs一遍,类似于线段树上二分的思想,输出答案。
自己没有写递归的写法,直接用的while里非递归。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 500010
char A[MAXN],ans[MAXN];
int N,T,K;
namespace SAM
{
int son[MAXN<<][],par[MAXN<<],len[MAXN<<],root,last,sz,size[MAXN<<];
inline void Init() {root=sz=last=;}
inline void Extend(int c)
{
int cur=++sz,p=last;
len[cur]=len[p]+; size[cur]=;
while (p && !son[p][c]) son[p][c]=cur,p=par[p];
if (!p) par[cur]=root;
else
{
int q=son[p][c];
if (len[p]+==len[q]) par[cur]=q;
else
{
int nq=++sz;
memcpy(son[nq],son[q],sizeof(son[nq])); len[nq]=len[p]+;
par[nq]=par[q];
while (p && son[p][c]==q) son[p][c]=nq,p=par[p];
par[cur]=par[q]=nq;
}
}
last=cur;
}
inline void Build() {Init(); for (int i=; i<=N; i++) Extend(A[i]-'a'+);}
int st[MAXN],id[MAXN<<],sum[MAXN<<];
inline void Pre()
{
for (int i=; i<=sz; i++) st[len[i]]++;
for (int i=; i<=N; i++) st[i]+=st[i-];
for (int i=; i<=sz; i++) id[st[len[i]]--]=i;
if (!T)
{
for (int i=sz; i>=; i--) size[i]=;
size[root]=;
for (int i=sz,Sum=; i>=; i--,Sum=)
{
for (int j=; j<=; j++)
Sum+=sum[son[id[i]][j]];
sum[id[i]]=Sum+;
}
}
else
{
for (int i=sz; i>=; i--)
size[par[id[i]]]+=size[id[i]];
size[root]=;
for (int i=sz; i>=; i--)
{
sum[id[i]]=size[id[i]];
for (int j=; j<=; j++)
sum[id[i]]+=sum[son[id[i]][j]];
}
}
}
inline void Query(int K)
{
int now=root,tot=;
while (K)
{
for (int i=; i<=; i++)
if (son[now][i])
if (sum[son[now][i]]>=K)
{
ans[++tot]='a'+i-;
K-=size[son[now][i]];
now=son[now][i];
break;
}
else K-=sum[son[now][i]]; }
ans[++tot]=;
}
}using namespace SAM;
int main()
{
scanf("%s",A+);
N=strlen(A+);
SAM::Build();
scanf("%d%d",&T,&K);
SAM::Pre();
if (sum[root]<K)
puts("-1");
else
Query(K),puts(ans+);
return ;
}
【BZOJ-3998】弦论 后缀自动机的更多相关文章
- bzoj 3998 弦论 —— 后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 关于相同子串算一个还是算多个,其实就是看一种状态的 right 集合是否加上 Pare ...
- BZOJ - 3998 弦论 (后缀自动机)
#include<cstdio> #include<cstring> #include<queue> using namespace std; typedef lo ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...
- BZOJ 3998 [TJOI2015]弦论 ——后缀自动机
直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...
- 【BZOJ3998】[TJOI2015]弦论 后缀自动机
[BZOJ3998][TJOI2015]弦论 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T ...
- BZOJ 2882: 工艺( 后缀自动机 )
把串S复制成SS然后扔进后缀自动机里, 从根选最小的儿子走, 走N步就是答案了...一开始还想写个treap的...后来觉得太麻烦..就用map了... ----------------------- ...
- [bzoj3998][TJOI2015]弦论-后缀自动机
Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...
- bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...
随机推荐
- 【H5疑难杂症】脱离文档流时的渲染BUG
BUG重现 最近机票团队在一个页面布局复杂的地方发现一个BUG,非常奇怪并且不好定位,这类问题一般最后都会到我这里,这个问题是,改变dom结构,页面却不渲染!!! 如图所示,我动态的改变了dom结构, ...
- 如何在Node.js中合并两个复杂对象
通常情况下,在Node.js中我们可以通过underscore的extend或者lodash的merge来合并两个对象,但是对于像下面这种复杂的对象,要如何来应对呢? 例如我有以下两个object: ...
- AlloyRenderingEngine文本框组件
写在前面 Github: https://github.com/AlloyTeam/AlloyGameEngine 在dom元素里,自带了input标签,设置其type为text,它就是一个文本框. ...
- JQ实现判断iPhone、Android设备
最近做了一版微信宣传页,通过JQ来判断设备,并进行下载 微信内置浏览器对下载链接进行了屏蔽,所以先进行判断,如果是微信内置浏览器,则跳转应用宝链接,如果不是,则判断是iPhone/Adroid/PC ...
- Java基础知识【下】( 转载)
http://blog.csdn.net/silentbalanceyh/article/details/4608360 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...
- 十种MYSQL显错注入原理讲解(一)
开篇我要说下,在<代码审计:企业级Web代码安全架构>这本书中讲十种MYSQL显错注入,讲的很清楚. 感兴趣请去读完,若处于某种原因没读还想了解,那请继续往下. 1.count,rand, ...
- ExtPB.Net:窗体应用技巧(2)在树形导航下打开弹出的win窗口
ExtPB.Net的demo程序有个树形导航菜单,里面的菜单打开的窗口放在右边的TabStrip控件中.我们可以设计win通过导航打开,但有时我们希望以弹出窗口的形式打开它,但怎么办呢?现在可以这样修 ...
- 浅析匿名函数、lambda表达式、闭包(closure)区别与作用
浅析匿名函数.lambda表达式.闭包(closure)区别与作用 所有的主流编程语言都对函数式编程有支持,比如c++11.python和java中有lambda表达式.lua和JavaScript中 ...
- iOS 自定义方法 - UIView扩展
示例代码 //#import <UIKit/UIKit.h>@interface UIView (LPCView)/** 上 */@property CGFloat top;/** 下 * ...
- Git从码云Clone代码到本地
Git从码云或者Github 克隆代码到本地 1.下载安装Git,傻瓜式下一步下一步即可... 2.配置Git: 2.1.选择你要clone到本地的路径:右键--->$ Git Bash Her ...