3998: [TJOI2015]弦论

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 2018  Solved: 662
[Submit][Status][Discuss]

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

第一行是一个仅由小写英文字母构成的字符串S

第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc
0 3

Sample Output

aab

HINT

N<=5*10^5

T<2
K<=10^9

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】弦论 后缀自动机的更多相关文章

  1. bzoj 3998 弦论 —— 后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 关于相同子串算一个还是算多个,其实就是看一种状态的 right 集合是否加上 Pare ...

  2. BZOJ - 3998 弦论 (后缀自动机)

    #include<cstdio> #include<cstring> #include<queue> using namespace std; typedef lo ...

  3. BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...

  4. BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...

  5. BZOJ 3998 [TJOI2015]弦论 ——后缀自动机

    直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...

  6. 【BZOJ3998】[TJOI2015]弦论 后缀自动机

    [BZOJ3998][TJOI2015]弦论 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T ...

  7. BZOJ 2882: 工艺( 后缀自动机 )

    把串S复制成SS然后扔进后缀自动机里, 从根选最小的儿子走, 走N步就是答案了...一开始还想写个treap的...后来觉得太麻烦..就用map了... ----------------------- ...

  8. [bzoj3998][TJOI2015]弦论-后缀自动机

    Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...

  9. bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...

随机推荐

  1. Atitit.eclise的ide特性-------abt 编译

    Atitit.eclise的ide特性-------abt 编译 为什么要在Intellij IDEA中使用Eclipse编译器 如果你使用Intellij Idea,你应该考虑使用Eclipse编译 ...

  2. Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结

    Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结 1. 什么是可扩展的应用程序?1 2. 松耦合(ioc)2 3. 接口的思考 2 4. 单一用途&模块化,小粒度化2 ...

  3. Gulp自动添加版本号

    推荐使用gulp-rev + gulp-rev-collector是比较方便的方法,结果如下: "/css/style.css" => "/dist/css/sty ...

  4. arcgis 许可异常的解决

    异常现象: arcgis 许可服务管理器中无法重新读取许可,许可服务启动后立即停止.         解决方法: 1.卸载license:安装新的license!重新破解,替换license文件夹BI ...

  5. react native初步常见问题

    首先按照资料一步步搭建环境运行,然后成功了,很激动,可是,安卓就是没这么容易成功,还是太年轻了 could not get batchedbridge, make sure your bundle i ...

  6. [Android]异步 layout inflation(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5829809.html 异步 layout inflation ...

  7. 面向初学者之烦人的mainactivity启动前的actionBAR

    相信各位初学者的童鞋都遇到过一个问题,(大神们就别喷我哦,多多帮帮指正,嘿嘿)那就是当你点开你开发的软件或者是dome时,会发现这么一个问题: 你曾今以为你的软件点开的时候是这样的: 然而事实是残酷的 ...

  8. C# 在Repeater 的ItemDataBound 如何转换e.Item.DataItem 的类型

    1.使用DataSet和DataTable绑定数据源时,用 DataRowView view = (DataRowView)e.Item.DataItem; 2.DataReader绑定数据源时,用 ...

  9. ASP.NET MVC 3 网站优化总结(一) 使用 Gzip 压缩

    网站开启 Gzip 压缩的好处相信很多人都已经清楚,这样做可以提高网站的性能.那么为什么很多网站没有开启 Gzip 压缩功能呢?原因有4点:防病毒软件.浏览器 bug.网站代理和服务器未配置. 使用 ...

  10. Atitit.工作流 与 规则引擎

    Atitit.工作流 与 规则引擎 1.1. 应用来说,通常分为三部分:界面.业务逻辑和存储1 1.2. 自定义操作系列1 1.3. 自定义按钮系列2 1.1. 应用来说,通常分为三部分:界面.业务逻 ...