【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 ...
随机推荐
- 关于Karaf Container 4.0.7
Karaf是Apache旗下的一个开源项目.Karaf同时也是一个基于OSGi的运行环境,Karaf提供了一个轻量级的OSGi容器,可以用于部署各种组件,应用程序.Karaf提供了很多 ...
- 利用github pages创建简单的网站
github.com 作为最流行的源代码管理工具已经风靡全球,同时在依托于github也衍生出了各种各样的应用,比如可以利用github搭建博客系统等等. 先换个话题,我们每人手头都或多或少有些&qu ...
- Android Weekly Notes Issue #228
Android Weekly Issue #228 October 23rd, 2016 Android Weekly Issue #228 本期内容包括: Android 7.1的App Short ...
- java知识总结(更新中)
一.java 数据类型 基本类型(byte.short.int. long. char.float.double.boolean) 数字类型 整数型:byte(8).short(16).int(32) ...
- Sql Server 2016 新功能——内置的 Temporal Tables
放假之前老大跟我提起了一下2016有个有趣的功能叫 Temporal Table ,今天去看了一下资料整理一下. 这个功能看上去像是临时表,但是其实是系统维护的一个历史记录表.(在某个程度上面比起我们 ...
- screen:多重视窗管理程序
screen:多重视窗管理程序 screen [-S SCREEN_NAME]: 创建窗口,可指定窗口名称,如果不指定,则是ID.$HOSTNAME screen -ls: 列出所有的screen窗口 ...
- Nginx+PHP On windows
前期准备 Nginx 下载 http://nginx.org/ PHP下载 PHP Windows binaries 问题 问题1: opened a DOS window to la ...
- C#相关开发视频
Quickly Generate C# Classes from JSON Responses .NET Compiler Platform ("Roslyn") for the ...
- uva 1599 ideal path(好题)——yhx
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGYAAAODCAYAAAD+ZwdMAAAgAElEQVR4nOy9L8/0ypH/Pa8givGiyC
- Lis日常维护
1.[问题]护士站打印LIs条码,出来是PDF格式的 [解决]在文件夹Client\NeusoftLis\Xml\Print.xml中把BarcodePrint Name的值改成安装的斑马打印机名(不 ...