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

后缀树用来划分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. codeforces 1B 模拟

    题目大意: 给出两种行列位置的表示方法,一个是Excel表示法,一个是(R,C)坐标表示.给出一种表示,输出另外一种表示. 基本思路: 模拟,首先判断是哪一种表示法,然后转换成另外一种表示方法: 我做 ...

  2. list去重jdk1.8

    List<Object> newList = ll.stream().distinct().collect(Collectors.toList()); //jdk8去重操作

  3. Vue学习笔记【5】——如何定义一个基本的Vue代码结构

    插值表达式{{}} 和 v-text 默认 v-text 是没有闪烁问题的: v-text会覆盖元素中原本的内容,但是 插值表达式只会替换自己的这个占位符,不会把 整个元素的内容清空 v-cloak ...

  4. 网关协议:CGI和WSGI

    通常服务器程序分为web服务器和应用程序服务器.web服务器是用于处理HTML文件,让客户可以通过浏览器进行访问,主流的web服务器有Apache.IIS.Nginx.lighthttpd等.应用服务 ...

  5. BZOJ 3238: [Ahoi2013]差异((单调栈+后缀数组)/(后缀树))

    [传送门[(https://www.lydsy.com/JudgeOnline/problem.php?id=3238) 解题思路 首先原式可以把\(len\)那部分直接算出来,然后通过后缀数组求\( ...

  6. 吉首大学校赛 I 滑稽树上滑稽果 (Lucas + 莫队)

    链接:https://ac.nowcoder.com/acm/contest/925/I来源:牛客网 题目描述 n个不同的滑稽果中,每个滑稽果可取可不取,从所有方案数中选取一种,求选取的方案中滑稽果个 ...

  7. 组合数学(math)

    组合数学(math) 题目描述 为了提高智商,zjy开始学习组合数学.某一天她解决了这样一个问题:“给一个网格图,其中某些格子有财宝.每次从左上角出发,只能往右或下走.问至少要走几次才能把财宝全部捡完 ...

  8. 为什么TCP 会粘包断包UDP不会

    TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发 ...

  9. POJ 1673 EXOCENTER OF A TRIANGLE(解三角形重心)

    题目链接:http://poj.org/problem?id=1673 AC代码: #include<cstdio> #include<cmath> #include<a ...

  10. Python 操作excel常见异常

    一.使用xlrd模块读取excel: 1.报错:IndexError: list index out of range,如下图 解决方法:reading_sheet.cell(1,0).value中c ...