后缀自动机求字典序第k小的串——p3975
又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机
后缀树用来划分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的更多相关文章
- hdu 5008 查找字典序第k小的子串
Boring String Problem Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Ot ...
- Leetcode 440.字典序第k小的数字
字典序第k小的数字 给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字. 注意:1 ≤ k ≤ n ≤ 109. 示例 : 输入: n: 13 k: 2 输出: 10 解释: 字典序的排 ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置
题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...
- str2int HDU - 4436 后缀自动机求子串信息
题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...
- SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解
题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...
- poj2886(线段树求序列第k小)
题目链接:https://vjudge.net/problem/POJ-2886 题意:n个人围成一个圈,每个人有姓名s和权值val两个属性,第一轮序号为k的人退出,并根据其val指定下一个人,val ...
- poj2182(线段树求序列第k小)
题目链接:https://vjudge.net/problem/POJ-2182 题意:有n头牛,从1..n编号,乱序排成一列,给出第2..n个牛其前面有多少比它编号小的个数,记为a[i],求该序列的 ...
- 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)
题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...
随机推荐
- asp.net网站Application_Start疑是不执行的现象
今天遇见了一个很诡异的事情,发布了新代码后,发现在Application_Start中读取的一些配置参数变为空了,最开始我以为是什么特殊的原因程序没有执行Application_Start,导致它们的 ...
- 再也不用字符串拼接dom元素了
<script type="text/html" id="tmp"> <div class="cla"> <u ...
- C++子类的构造函数后面加:冒号的作用(转)
在C++类的构造函数中经常会看到如下格式的写法: MyWindow::MyWindow(QWidget* parent , Qt::WindowFlags flag) : QMainWindow(pa ...
- js中数据操作的某些思想
1,默认数据的复用 写成function的return形式缓存在变量中,用的时候直接执行fun就行了 例如 有文件text.js里面的对象是export default ()=>({aa:55, ...
- 统计所有小于非负整数 n 的质数的数量,埃拉托斯特尼筛法
素数的定义:质数又称素数.一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数. 1.暴力算法: 令i=2; 当i<n的时候,我们循环找出2-i的质数,即让i%(2~i-1), ...
- nuxt.js 本地开发跨域问题(Access-Control-Allow-Origin)及其解决方案
先运行npm i @gauseen/nuxt-proxy -D 再nuxt.config.js的module.exports 里面添加如下代码 modules:[ '@nuxtjs/axios', / ...
- homebrew -- mac os 系统下的 apt-get、yum
linux下有很方便的包管理器如:apt-get.yum,mac下也有类似的工具:Homebrew 和 Fink.MacPort.Flink是直接编译好的二进制包,MacPorts是下载所有依赖库的源 ...
- 排序算法(三)堆排序及有界堆排序Java实现及分析
1.堆排序基数排序适用于大小有界的东西,除了他之外,还有一种你可能遇到的其它专用排序算法:有界堆排序.如果你在处理非常大的数据集,你想要得到前 10 个或者前k个元素,其中k远小于n,它是很有用的. ...
- CF C. Fly
题目 题目大意:第一行给出一个数n,代表有n个点,第二行给出火箭的自重,第三行给出每个点去时每吨需要的燃料,第四行给出每个点返程时每吨需要的燃料.求出发时携带的最小燃料数 分析:这题我们只要逆向思维就 ...
- java文件上传方式1servlet 方式2springmvc
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletExcepti ...