题目链接
链接是洛谷有翻译的链接。

题意:
给你一个字符串,有T次询问,每次问你在整个字符串中排名为k的子串是哪一个。字符串长度<=90000,T<=500,只统计本质不同的串。

题解:
后缀自动机题,因为后缀自动机有着很强的处理子串的能力。

看到排名第k,我们可能会想到主席树,但是显然主席树是没法维护具体某个字符串,但是主席树查询第k大的思想我们是可以使用的。主席树的方法是看左子树的size是否比k大,然后来确定进入左子树还是把k减去左子树的size进入右子树。

其实在后缀自动机是我们也是可以用到这个思想的。我们先建出给出字符串的后缀自动机,然后我们其实可以发现,后缀自动机上的所有转移边构成了一个DAG(也是后缀自动机的性质),那么对于DAG,我们是可以拓扑排序的。这里可以用一种比较特殊的拓扑排序,这种写法有点类似与基数排序,我们把长的串排在短的串后面,后建的节点排在先建的节点后面,这样一定是一种合法的拓扑序。然后我们根据这个拓扑序,我们用反着的拓扑序,求出SAM上每个点能到达的所有点的个数,也就是原串中它的后缀个数每个点本身的size都是1,因为从起点到每个点都会形成一个子串。这样我们可以像在主席树上一样,从根开始走,从小的字母往大的字母尝试走,看走到哪个字母正好超过当前k,如果当前枚举到的出边到达的点的size比k小,我们就减去这个size;如果比k大了,就不再减size,转而输出那个字母,然后走过去。这样说可能不是很容易说明白,具体可以看看代码。

代码

#include <bits/stdc++.h>
using namespace std;int T,n,len[400010],fa[400010],cnt=1,rt=1,lst=1,ch[400010][26];
int sz[400010],a[400010],rk[400010],m;
char s[100010];
inline void insert(int x)
{int cur=++cnt,pre=lst;lst=cur;len[cur]=len[pre]+1;for(;pre&&!ch[pre][x];pre=fa[pre])ch[pre][x]=cur;if(!pre)fa[cur]=rt;else{int ji=ch[pre][x];if(len[ji]==len[pre]+1)fa[cur]=ji;else{int gg=++cnt;len[gg]=len[pre]+1;memcpy(ch[gg],ch[ji],sizeof(ch[ji]));fa[gg]=fa[ji];fa[ji]=fa[cur]=gg;for(;pre&&ch[pre][x]==ji;pre=fa[pre])ch[pre][x]=gg;}}
}
inline void query(int x)
{int ji=rt;while(x){if(ji!=rt)--x;if(x<=0)break;for(int i=0;i<=25;++i){if(sz[ch[ji][i]]<x)x-=sz[ch[ji][i]];else{printf("%c",'a'+i);ji=ch[ji][i];break;}}}printf("\n");
}
int main()
{scanf("%s",s+1);n=strlen(s+1);for(int i=1;i<=n;++i)insert(s[i]-'a');for(int i=cnt;i>=1;--i)a[len[i]]++;for(int i=1;i<=n;++i)a[i]+=a[i-1];for(int i=cnt;i>=1;--i)rk[a[len[i]]--]=i;for(int i=1;i<=cnt;++i)sz[i]=1;for(int i=cnt;i>=1;--i){for(int j=0;j<=25;++j)sz[rk[i]]+=sz[ch[rk[i]][j]];}scanf("%d",&T);while(T--){scanf("%d",&m);query(m);}return 0;
}

SPOJ7258 SUBLEX 后缀自动机相关推荐

  1. SPOJ 7258 SUBLEX 后缀自动机

    求第k大子串. 按拓扑序处理出一个点往后有多少条路径到终态. 答案就很明显了. #include <cstring> #include <cstdio> #define FOR ...

  2. 【SPOJ】7258. Lexicographical Substring Search(后缀自动机)

    http://www.spoj.com/problems/SUBLEX/ 后缀自动机系列完成QAQ...撒花..明天or今晚写个小结? 首先得知道:后缀自动机中,root出发到任意一个状态的路径对应一 ...

  3. SP7258 SUBLEX (后缀自动机)

    SUBLEX - Lexicographical Substring Search - 洛谷 题意 给定一个字符串,求本质不同排名第k小的子串 输入格式: 第一行给定主串(len<=90000) ...

  4. 从零开始の后缀自动机

    后缀自动机,一个处理字符串问题的神器.听起来很神圣,貌似很难写.其实代码实现并不复杂,萌新估计都能学会. 以前听学长们讲过好多次也看过陈立杰的课件,都不是很明白.今天终于弄明白了,就写一个让大家都能看 ...

  5. [学习笔记]后缀自动机

    解决大部分字符串问题的大杀器 给一下clj课件:戳我 SAM是一个博大精深的算法.虽然没有像网络流家族,Tarjan家族一样拉帮结派,但是自身包含很多方法. 一.前言 字符串常见问题:各种匹配 1.L ...

  6. 后缀自动机 AC自动机

    trie树可遍历出所有无重复后缀,通过后缀遍历前缀可得到所有子串:后缀链接把所有后缀相同的状态(以当前节点为endpos的子串)连接起来,便有了类似KMP的next数组的性质.             ...

  7. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做...

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. 1 #include <cstdlib> 2 ...

  8. 【POJ1509】Glass Beads 【后缀自动机】

    题意 给出一个字符串,求它的最小表示法. 分析 这个题当然可以用最小表示法做啦!但是我是为了学后缀自动机鸭! 我们把这个字符串长度乘二,然后建SAM,然后在SAM上每次跑最小的那个字母,找出长度为n的 ...

  9. bzoj 2946 [Poi2000]公共串——后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2946 对每个串都建一个后缀自动机,然后 dfs 其中一个自动机,记录同步的话在别的自动机上走 ...

最新文章

  1. HashSet的使用
  2. serv-u 自定义html,Serv-U FTP鲜为人知的技巧(自定义欢迎界面)
  3. [机械]“重工业面临两大危机”——向文波(三一重工股份有限公司执行总裁)
  4. 《Effective C#》的读书笔记
  5. c#.net——c#.net异步实现网页信息爬取
  6. 用for循环打印出九九乘法表
  7. ISO C90 forbids mixed declarations and code 警告
  8. android自定义广播实现app完全退出
  9. Activiti6常见错误汇总
  10. 提供搜题公众号题库接口
  11. 军事 - [纪录片]古兵器大揭秘
  12. docker中 scp root远程至普通用户
  13. 陈老师排课12A版的手工调课的方法
  14. 计算机操作系统——银行家算法
  15. 使用Selenium从IEEE与谷歌学术批量爬取BibTex文献引用
  16. jbpm工作流动态会签
  17. 记javascript设计模式
  18. 2018年如何挣钱 ?
  19. Android Hawk数据库 github开源项目,深入理解JVM的核心知识点
  20. caj转换成word转换器下载后如何操作?

热门文章

  1. win10原生输入法间隔变大解决办法
  2. vue 自定义生成表格 并且可以输入
  3. 重磅出击,20张图带你彻底了解ReentrantLock加锁解锁的原理
  4. 252T网盘资源包括:
  5. 对文件夹下所有的文件一键改名
  6. 聊城大学计算机学院宿管部,计算机学院
  7. Linux搭建Nextcloud,打造属于您的专属网盘
  8. 北京雾霾越来越重的原因找到了!
  9. 罗技计算机配置存入板载内存,板载内存 没有驱动也能自定义_鼠标_键鼠导购-中关村在线...
  10. print()函数的使用