题目传送门

  传送门I

  传送门II

题目大意

  给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它。

  考虑后缀Trie。依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] - height[i]$。

  求出$height$数组后,求一求本质不同的子串个数的前缀和,可以对每个询问二分。

  这里可以直接离线,$O(n + m)$扫一扫就好了。

Code

  1. /**
  2. * SPOJ
  3. * Problem#SUBLEX
  4. * Accepted
  5. * Time: 30ms
  6. * Memory: 19456k
  7. */
  8. #include <bits/stdc++.h>
  9. using namespace std;
  10. typedef bool boolean;
  11.  
  12. typedef class Pair3 {
  13. public:
  14. int x, y, id;
  15. }Pair3;
  16.  
  17. typedef class Query {
  18. public:
  19. int k, s, t, id;
  20.  
  21. boolean operator < (Query b) const {
  22. return k < b.k;
  23. }
  24. }Query;
  25.  
  26. const int N = 1e5 + , M = ;
  27.  
  28. int n, m;
  29. char str[N], bs[N];
  30. int rk[N << ], sa[N], hei[N], cnt[N];
  31. Pair3 ps[N], buf[N];
  32. Query qs[M];
  33.  
  34. inline void init() {
  35. scanf("%s", str + );
  36. n = strlen(str + );
  37. scanf("%d", &m);
  38. for (int i = ; i <= m; i++)
  39. scanf("%d", &qs[i].k), qs[i].id = i;
  40. }
  41.  
  42. inline void radix_sort(Pair3* x, Pair3* y) {
  43. int m = ((n > ) ? (n) : ());
  44. memset(cnt, , sizeof(int) * (m + ));
  45. for (int i = ; i <= n; i++) cnt[x[i].y]++;
  46. for (int i = ; i <= m; i++) cnt[i] += cnt[i - ];
  47. for (int i = ; i <= n; i++) y[cnt[x[i].y]--] = x[i];
  48. memset(cnt, , sizeof(int) * (m + ));
  49. for (int i = ; i <= n; i++) cnt[y[i].x]++;
  50. for (int i = ; i <= m; i++) cnt[i] += cnt[i - ];
  51. for (int i = n; i; i--) x[cnt[y[i].x]--] = y[i];
  52. }
  53.  
  54. inline void build_sa() {
  55. for (int i = ; i <= n; i++)
  56. rk[i] = str[i];
  57. for (int k = , dif = ; k <= n; k <<= , dif = ) {
  58. for (int i = ; i <= n; i++)
  59. ps[i].x = rk[i], ps[i].y = rk[i + k], ps[i].id = i;
  60. radix_sort(ps, buf);
  61. rk[ps[].id] = ++dif;
  62. for (int i = ; i <= n; i++)
  63. rk[ps[i].id] = (dif += (ps[i].x != ps[i - ].x || ps[i].y != ps[i - ].y));
  64. if (dif == n)
  65. break;
  66. }
  67. for (int i = ; i <= n; i++)
  68. sa[rk[i]] = i;
  69. }
  70.  
  71. inline void get_height() {
  72. for (int i = , j, k = ; i <= n; i++) {
  73. if (k) k--;
  74. if (rk[i] > ) {
  75. for (j = sa[rk[i] - ]; i + k <= n && j + k <= n && str[i + k] == str[j + k]; k++);
  76. hei[rk[i]] = k;
  77. } else
  78. hei[] = ;
  79. }
  80. }
  81.  
  82. inline void solve() {
  83. build_sa();
  84. get_height();
  85. // for (int i = 1; i <= n; i++)
  86. // cerr << hei[i] << " ";
  87. // cerr << endl;
  88. sort(qs + , qs + m + );
  89. long long cur = ;
  90. for (int i = , nq = , delta; i <= n && nq <= m; i++) {
  91. delta = n - sa[i] + - hei[i];
  92. if (cur + delta < qs[nq].k)
  93. cur += delta;
  94. else {
  95. qs[nq].s = sa[i], qs[nq].t = sa[i] + hei[i] + (qs[nq].k - cur);
  96. nq++, i--;
  97. }
  98. }
  99. for (int i = ; i <= m; i++)
  100. while (qs[i].id != i)
  101. swap(qs[qs[i].id], qs[i]);
  102. for (int i = ; i <= m; i++) {
  103. int len = qs[i].t - qs[i].s;
  104. memcpy(bs, str + qs[i].s , len);
  105. bs[len] = ;
  106. puts(bs);
  107. }
  108. }
  109.  
  110. int main() {
  111. init();
  112. solve();
  113. return ;
  114. }

SPOJ SUBLEX Lexicographical Substring Search - 后缀数组的更多相关文章

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

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

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

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

  3. spoj SUBLEX (Lexicographical Substring Search) RE的欢迎来看看

    SPOJ.com - Problem SUBLEX 这么裸的一个SAM,放在了死破OJ上面就是个坑. 注意用SAM做的时候输出要用一个数组存下来,然后再puts,不然一个一个字符输出会更慢. 还有一个 ...

  4. Spoj SUBLEX - Lexicographical Substring Search

    Dicription Little Daniel loves to play with strings! He always finds different ways to have fun with ...

  5. SP7258 SUBLEX - Lexicographical Substring Search - 后缀自动机,dp

    给定一个字符串,求本质不同排名第k小的子串 Solution 后缀自动机上每条路径对应一个本质不同的子串 按照 TRANS 图的拓扑序,DP 计算出每个点发出多少条路径 (注意区别 TRANS 图的拓 ...

  6. SPOJ 7258 Lexicographical Substring Search [后缀自动机 DP]

    题意:给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个. 第一道自己做的1A的SAM啦啦啦 很简单,建SAM后跑kth就行了 也需要按val基数排序倒着 ...

  7. SPOJ7258 SUBLEX - Lexicographical Substring Search(后缀自动机)

    Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...

  8. spoj SUBLEX - Lexicographical Substring Search【SAM】

    先求出SAM,然后考虑定义,点u是一个right集合,代表了长为dis[son]+1~dis[u]的串,然后根据有向边转移是添加一个字符,所以可以根据这个预处理出si[u],表示串u后加字符能有几个本 ...

  9. SP7258 SUBLEX - Lexicographical Substring Search(后缀自动机)

    传送门 解题思路 首先建\(sam\),然后在拓扑序上\(dp\)一下,把每个点的路径数算出来,然后统计答案时就在自动机上\(dfs\)一下,仿照平衡树那样找第\(k\)小. 代码 #include& ...

随机推荐

  1. Cocos Creator 键盘监听事件

    键盘事件键盘.设备重力传感器此类全局事件是通过函数 cc.systemEvent.on(type, callback, target) 注册的.cc.SystemEvent.EventType.KEY ...

  2. 等比数列二分求和(logn复杂度)

    看完这个之后,感觉数学简直太厉害了 转载自:http://blog.csdn.net/acdreamers/article/details/7851144 今天我们学习如何有效地求表达式的值.对于这个 ...

  3. SpringMVC.入门篇.一.HelloWorld

    SpringMVC.入门篇<一>HelloWorld 项目包结构如下: HelloController.java 代码 package com.charles.controller; im ...

  4. LeetCode110.平衡二叉树

    一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1. 示例 1: 给定二叉树 [3,9,20,null,null,15,7] 3 / \ 9 20 / \ 15 7 返回 true . 示例 ...

  5. 软工网络15团队作业4——Alpha阶段敏捷冲刺1.0

    软工网络15团队作业4--Alpha阶段敏捷冲刺1.0 1. 各个成员在 Alpha 阶段认领的任务,以及整个项目预期的任务量(使用整数表示,与项目预估的总工作小时数一致.比如项目A预估需120小时才 ...

  6. strlen实现

    1.strlen函数. 普通版实现方法, int strlen( char *s) { int length = 0; while(*s++) length++; return length; } 优 ...

  7. php核心纪要 整理

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 20155228 实验三 敏捷开发与XP实践

    20155228 实验三 敏捷开发与XP实践 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)>& ...

  9. 20155228 2016-2017-2 《Java程序设计》第10周学习总结

    20155228 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 网络 网络是能够波此通信的计算机的集合根据范}到的宽度,网络可以分为局域网和广域网.LAN ...

  10. ResourceBundle与Properties读取配置文件

    ResourceBundle与Properties的区别在于ResourceBundle通常是用于国际化的属性配置文件读取,Properties则是一般的属性配置文件读取. ResourceBundl ...