又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机

后缀树用来划分endpos集合,并且维护后缀之间的关系,此时每个结点代表的是一些后缀相同且长度连续的子串

自动机用来处理边的转移,或者用来解决串的匹配问题,此时每个结点代表的只是一个串,这个串等于从root开始到这结点经过的路径,由于路径可能有很多条,所以对应到后缀树上,就是有一段连续的串啦

字典序第k小的串刚好可以用SAM的性质解决

/*
题目要求考虑两种情况:
首先来考虑算重复子串的情况
处理后缀树:先求出每个状态endpos的大小(即这个状态代表的所有串出现的次数)size[i](endpos的大小即该状态的后缀子树的大小,所有的前缀结点贡献为1,克隆结点大小为0)
处理自动机:自底向上求出从每个状态出发能形成的子串个数 sum[i]+=sum{sum[j]} ,初始有sum[i]=size[i](即从这种状态开始有多少不同的子串,当然这种状态本身的方案数也算)
最后以root为起点,在自动机上进行搜索即可,具体搜索方式类似于多叉树(DAG)查询
然后来考虑不算重复子串的情况
处理后缀树:求endpos的大小
处理自动机:自底向上求每个状态出发能形成的子串个数sum[i]=sum{sum[j]} 初始有sum[i]=1,即这个状态的每个串认为只出现一次
再换一种思路:其实只要维护处每个状态作为起点的不同路径数即可
搜索过程不变
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
long long T,K;
char s[maxn];
struct SAM{
int last,cnt;
int nxt[maxn<<][];
int len[maxn<<];
int link[maxn<<];
int size[maxn<<];
long long sum[maxn<<];//sum[i]表示从状态i开始的子串总数
SAM(){
last=cnt=;
}
void add(int c){
int p=last,np=last=++cnt;
len[np]=len[p]+;
size[np]=;
for(;p&&!nxt[p][c];p=link[p])
nxt[p][c]=np;
if(!p){link[np]=;return;} int q=nxt[p][c];
if(len[q]==len[p]+){link[np]=q;return;} int clone=++cnt;
link[clone]=link[q];
len[clone]=len[p]+;
memcpy(nxt[clone],nxt[q],sizeof nxt[q]);
link[q]=link[np]=clone;
for(;p&&nxt[p][c]==q;p=link[p])
nxt[p][c]=clone;
}
int id[maxn<<],t[maxn<<];
void sort(){
for(int i=;i<=cnt;i++)t[len[i]]++;
for(int i=;i<=cnt;i++)t[i]+=t[i-];
for(int i=;i<=cnt;i++)id[t[len[i]]--]=i;
}
void work(){//求子串的总数
//处理后缀树上的endpos
for(int i=cnt;i>=;i--)
size[link[id[i]]]+=size[id[i]];
for(int i=;i<=cnt;i++)
if(T==)sum[i]=size[i]=;//要求去重,每个状态代表的串只统计一次
else sum[i]=size[i];
size[]=sum[]=;
//自底向上处理自动机
for(int i=cnt;i>=;i--)
for(int j=;j<;j++)
if(nxt[id[i]][j])
sum[id[i]]+=sum[nxt[id[i]][j]];
}
}p; void print(long long now,long long k){
if(k<=p.size[now])return;//如果这个结点代表的串也不能走完,返回
k-=p.size[now];
for(int i=;i<;i++){
int tmp=p.nxt[now][i];
if(!tmp)continue;
if(k>p.sum[tmp]){
k-=p.sum[tmp];
continue;
} putchar(i+'a');//沿着这个状态往下搜
print(tmp,k);
return;
}
} int main(){
scanf("%s%lld%lld",s,&T,&K);
int len=strlen(s);
for(int i=;i<len;i++)
p.add(s[i]-'a'); p.sort(); p.work(); if(p.sum[]<K)printf("-1");
else print(,K);
puts(""); }

后缀自动机求字典序第k小的串——p3975的更多相关文章

  1. hdu 5008 查找字典序第k小的子串

    Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Ot ...

  2. Leetcode 440.字典序第k小的数字

    字典序第k小的数字 给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字. 注意:1 ≤ k ≤ n ≤ 109. 示例 : 输入: n: 13 k: 2 输出: 10 解释: 字典序的排 ...

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

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

  4. Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置

    题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...

  5. str2int HDU - 4436 后缀自动机求子串信息

    题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...

  6. SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解

    题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...

  7. poj2886(线段树求序列第k小)

    题目链接:https://vjudge.net/problem/POJ-2886 题意:n个人围成一个圈,每个人有姓名s和权值val两个属性,第一轮序号为k的人退出,并根据其val指定下一个人,val ...

  8. poj2182(线段树求序列第k小)

    题目链接:https://vjudge.net/problem/POJ-2182 题意:有n头牛,从1..n编号,乱序排成一列,给出第2..n个牛其前面有多少比它编号小的个数,记为a[i],求该序列的 ...

  9. 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)

    题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...

随机推荐

  1. pip配置阿里云源

    Windows:打开计算机,在地址栏输入%appdata%,回车,进入用户文件夹,新建文件夹,命名为pip 在pip下新建pip.ini,输入以下内容 [global] timeout=6000ind ...

  2. python 对redis 键值对的操作

    我们可以将Redis中的Hashes类型看成具有String Key和String Value的键值对容器.类似python中的dict,javascript的jaon,java 的map,每一个Ha ...

  3. 分布式消息中间件(二)ActiveMQ

    一.概述 Apache出品,最流行的,能力强劲的开源消息总线. 1.JMS规范 Java消息服务(Java Message Service,即JMS)应用程序接口是一个Java平台中关于面向消息中间件 ...

  4. Vue学习笔记【12】——过滤器

    概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化.过滤器可以用在两个地方:mustache 插值和 v-bind 表达式.过滤器应该被添加在 JavaScript 表达式的尾部,由 ...

  5. RRT路径规划算法(matlab实现)

    基于快速扩展随机树(RRT / rapidly exploring random tree)的路径规划算法,通过对状态空间中的采样点进行碰撞检测,避免了对空间的建模,能够有效地解决高维空间和复杂约束的 ...

  6. phpstorm使用说明

    1.phpstorm软件可以直接断点调试php代码.具体配置方法参考 http://blog.csdn.net/qq4551091/article/details/55258664 就可以了,不过只要 ...

  7. linux python3 venv 虚拟环境报错 [-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 2.

    解决办法: 先创建没有pip的虚拟环境,然后启动虚拟环境后,再安装pip 办法一: 亲测失败了... python3 -m venv --without-pip py36env 办法二 sudo ap ...

  8. sea.js模块加载工具

    seajs的使用 seajs是一个jS模块加载器,由淘宝前端架构师玉伯开发,它可以解决命名空间污染,文件依赖的问题.可以在一个js文件中引入另外一个js.require('a.js') 1.安装 np ...

  9. redis-trib.rb创建集群失败

    yum安装ruby: yum install -y rubyyum install -y rubygems //安装rubygemgem install redis //安装redis的接口包gem ...

  10. CSS中复选框单选框与常用12px文字不对齐问题(转载)

    原文  http://www.cnblogs.com/aobingyan/p/3823556.html,有删改 目前中文网站上面的文字,绝大多数网站的主流文字大小为12px,因为在目前高分辨率显示器屏 ...