题目传送门

思路:按字典序,小的字符优先选取。对于一个字符,如果以这个字符开头的子串大于等于k个,那说明这个字符是应该选的,并且选完之后,可能还要继续选。如果以这个字符开头的子串小于k个,说明这个字符不能选,因为选完这个字符,后面无论怎么构造子串,都构造不出第k大的子串。

  所以关键点就在于我们要统计每个字符开头的后面的子串数量,核心代码如下:

  1. void topSort(){
  2. for(int i=;i<=tot;i++)c[len[i]]++;
  3. for(int i=;i<=tot;i++)c[i]+=c[i-];
  4. for(int i=tot;i>;i--)a[c[len[i]]--]=i;
  5. for(int i=tot;i>;i--){
  6. int p=a[i];
  7. r[p]++;
  8. for(int j=;j<;j++){
  9. if(ch[p][j]){
  10. r[p]+=r[ch[p][j]];
  11. }
  12. }
  13. }
  14. }

为什么我们拓扑序从大到小更新是正确的呢?因为在自动机上,$ch[p][c]$的拓扑序必定是大于$p$的拓扑序的,因为$ch[p][c]$的$longest$比较大,所以这样更新不会遗留也不会重复。

还有一个要注意的点是,在查询的时候,如果以某一个字符开头的子串大于k,我们选取了这个字符,此时k也要减一,因为选到这个字符截止也是一种方案。

  1. #include<bits/stdc++.h>
  2. #define clr(a,b) memset(a,b,sizeof(a))
  3. using namespace std;
  4. typedef long long ll;
  5. const int inf=0x3f3f3f3f;
  6. const ll mod=1e9+;
  7. const int maxn=;
  8. char s[maxn];
  9. int len[maxn<<],ch[maxn<<][],fa[maxn<<],tot=,root=,last=,siz,r[maxn<<],vis[maxn<<];
  10. int a[maxn<<],c[maxn<<],ans[maxn<<];
  11. ll dp[maxn<<];
  12. void extend(int x){
  13. int now=++tot,pre=last;
  14. last=now,len[now]=len[pre]+;
  15. while( pre && !ch[pre][x]){
  16. ch[pre][x]=now;
  17. pre=fa[pre];
  18. }
  19. if(!pre)fa[now]=root;
  20. else{
  21. int q = ch[pre][x];
  22. if(len[q]==len[pre]+)fa[now]=q;
  23. else {
  24. int nows=++tot;
  25. memcpy(ch[nows],ch[q],sizeof(ch[q]));
  26. len[nows]=len[pre]+;
  27. fa[nows]=fa[q];
  28. fa[q]=fa[now]=nows;
  29. while(pre&&ch[pre][x]==q){
  30. ch[pre][x]=nows;
  31. pre=fa[pre];
  32. }
  33. }
  34. }
  35. }
  36. void topSort(){
  37. for(int i=;i<=tot;i++)c[len[i]]++;
  38. for(int i=;i<=tot;i++)c[i]+=c[i-];
  39. for(int i=tot;i>;i--)a[c[len[i]]--]=i;
  40. for(int i=tot;i>;i--){
  41. int p=a[i];
  42. r[p]++;
  43. for(int j=;j<;j++){
  44. if(ch[p][j]){
  45. r[p]+=r[ch[p][j]];
  46. }
  47. }
  48. }
  49. }
  50. void query(int k){
  51. int now=root;
  52. while(k){
  53. for(int i=;i<;i++){
  54. if(ch[now][i]){
  55. int p=ch[now][i];
  56. if(r[p]>=k){
  57. now=p;
  58. putchar('a'+i);
  59. k--;
  60. break;
  61. }else{
  62. k-=r[p];
  63. }
  64. }
  65. }
  66. }
  67. puts("");
  68. }
  69. int main(){
  70. scanf("%s",s);
  71. siz=strlen(s);
  72. for(int i=;i<siz;i++){
  73. int p=s[i]-'a';
  74. extend(p);
  75. }
  76. topSort();
  77. int n,k;
  78. cin>>n;
  79. while(n--){
  80. cin>>k;
  81. query(k);
  82. }
  83.  
  84. }

SPOJ Lexicographical Substring Search 求字典序第k大子串 后缀自动机的更多相关文章

  1. SPOJ Lexicographical Substring Search 后缀自动机

    给你一个字符串,然后询问它第k小的factor,坑的地方在于spoj实在是太慢了,要加各种常数优化,字符集如果不压缩一下必t.. #pragma warning(disable:4996) #incl ...

  2. spoj 7258 Lexicographical Substring Search (后缀自动机)

    spoj 7258 Lexicographical Substring Search (后缀自动机) 题意:给出一个字符串,长度为90000.询问q次,每次回答一个k,求字典序第k小的子串. 解题思路 ...

  3. SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组

    SUBLEX - Lexicographical Substring Search Little Daniel loves to play with strings! He always finds ...

  4. SPOJ SUBLEX 7258. Lexicographical Substring Search

    看起来像是普通的SAM+dfs...但SPOJ太慢了......倒腾了一个晚上不是WA 就是RE ..... 最后换SA写了...... Lexicographical Substring Searc ...

  5. 【SPOJ 7258】Lexicographical Substring Search

    http://www.spoj.com/problems/SUBLEX/ 好难啊. 建出后缀自动机,然后在后缀自动机的每个状态上记录通过这个状态能走到的不同子串的数量.该状态能走到的所有状态的f值的和 ...

  6. [SPOJ7258]Lexicographical Substring Search

    [SPOJ7258]Lexicographical Substring Search 试题描述 Little Daniel loves to play with strings! He always ...

  7. poj_1037 动态规划+字典序第k大

    题目大意 给定n个数字,规定一种 cute 排序:序列中的数字大小为严格的波浪形,即 a[0] > a[1] < a[2] > a[3] < .... 或者 a[0] < ...

  8. POJ2761---Feed the dogs (Treap求区间第k大)

    题意 就是求区间第k大,区间 不互相包含. 尝试用treap解决一下 第k大的问题. #include <set> #include <map> #include <cm ...

  9. POJ 2104 K-th Number ( 求取区间 K 大值 || 主席树 || 离线线段树)

    题意 : 给出一个含有 N 个数的序列,然后有 M 次问询,每次问询包含 ( L, R, K ) 要求你给出 L 到 R 这个区间的第 K 大是几 分析 : 求取区间 K 大值是个经典的问题,可以使用 ...

随机推荐

  1. DIV+CSS布局时, DIV的高度和宽度特性

    这个没有特别的做要求,你要根据你自己的页面整体布局来设置,还有根据div的特性来设置,div默认情况是宽度最大化(100%).高度最小化,高度随着内容自动伸展: 一般情况做网页的话,大部分都是固定了总 ...

  2. CentOS 最新版的下载地址 + 版本选择详解

    CentOS 最新版的下载地址 + 版本选择详解 发现越来越多的机关单位.事业单位开始使用 Linux 作为主要服务器,毕竟,Linux的稳定性和高效性是众所周知的,所以我也打算把自己这一块技术加强一 ...

  3. centos环境下创建数据库和表的方法

    centos环境下创建数据库和表的方法 //查询数据库的命令: mysql> SHOW DATABASES; +--------------------+ | Database         ...

  4. Gym 101201F Illumination (Two-Sat)

    题意:一个n*n的房子,有很多灯,每个格子只能被上下方向照一次.左右方向照一次,每个灯可以选择上下或是左右照,照明长度以自身位置为中心,占用2*r+1个格子.问能否安排一种方案,使所有格子满足条件. ...

  5. 团体程序设计天梯赛L1-019 谁先倒 2017-03-22 17:35 33人阅读 评论(0) 收藏

    L1-019. 谁先倒 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳 ...

  6. java并发编程实战:第五章----基础构建模块

    委托是创建线程安全类的一个最有效的策略:只需让现有的线程安全类管理所有的状态即可. 一.同步容器类 1.同步容器类的问题 同步容器类都是线程安全的,容器本身内置的复合操作能够保证原子性,但是当在其上进 ...

  7. CentOS 7 IPv6关闭

    你可以用两个方法做到这个.方法 1编辑文件/etc/sysctl.conf,vi /etc/sysctl.conf添加下面的行:net.ipv6.conf.all.disable_ipv6 =1net ...

  8. C# SM加密

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using Org.Boun ...

  9. Cookie客户端缓存.Session.Application

    Cookie客户端缓存. 1.引言 随着浏览器的处理能力不断增强,越来越多的网站开始考虑将数据存储在「客户端」,那么久不得不谈本地存储了. 本地存储的好处: 一是避免取回数据前页面一片空白,如果不需要 ...

  10. Javascript 535种方式!!!实现页面重载

    原文地址: http://www.phpied.com/files/location-location/location-location.html 完全出于好玩,竟然有人整理了500多种方法来实现刷 ...