本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息。由于题目要求子串起始下标尽可能小。所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串长度的范围。通过RMQ求出这个范围中最小的sa。

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <string>
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <queue>
  8. #include <stack>
  9. #include <map>
  10. #include <set>
  11. #include <cmath>
  12. #include <ctime>
  13. #include <cassert>
  14. #include <sstream>
  15. using namespace std;
  16.  
  17. const int N=;
  18.  
  19. int MIN(int a,int b){return a<b?a:b;}
  20. int MAX(int a,int b){return a>b?a:b;}
  21.  
  22. int val[N];
  23. struct RMQ {
  24. int dp[N][];
  25. int (*cmp) (int,int);
  26. void setMin(){cmp=MIN;}
  27. void setMax(){cmp=MAX;}
  28. void init(int n,int *val) {
  29. for (int i=; i<=n; i++)
  30. dp[i][]=val[i];
  31. for (int j=; (<<j)<=n; j++) {
  32. int k=<<(j-);
  33. for (int i=; i+k<=n; i++)
  34. dp[i][j]=cmp(dp[i][j-],dp[i+k][j-]);
  35. }
  36. }
  37. int query(int a,int b) {
  38. if (a>b) swap(a,b);
  39. int dis=b-a+;
  40. int k=log((double)dis)/log(2.0);
  41. return cmp(dp[a][k],dp[b-(<<k)+][k]);
  42. }
  43. }rmq;
  44. char s[N];
  45. struct SuffixArray {;
  46. int sa[N];
  47. int t1[N],t2[N],c[N];
  48. int rk[N],height[N];
  49. long long sum[N];
  50. inline int cmp(int *r,int a,int b,int l){
  51. return r[a]==r[b]&&r[a+l]==r[b+l];
  52. }
  53. void calcSA (char *s,int n,int m) {
  54. int i,j,p,*x=t1,*y=t2;
  55. for(i=;i<m;i++)c[i]=;
  56. for(i=;i<n;i++)c[x[i]=s[i]]++;
  57. for(i=;i<m;i++)c[i]+=c[i-];
  58. for(i=n-;i>=;i--)sa[--c[x[i]]]=i;
  59. for(j=;j<=n;j<<=){
  60. p=;
  61. for(i=n-j;i<n;i++)y[p++]=i;
  62. for(i=;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
  63. for(i=;i<m;i++)c[i]=;
  64. for(i=;i<n;i++)c[x[y[i]]]++;
  65. for(i=;i<m;i++)c[i]+=c[i-];
  66. for(i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
  67. swap(x,y);
  68. p=;x[sa[]]=;
  69. for(i=;i<n;i++)
  70. x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
  71. if(p>=n)break;
  72. m=p;
  73. }
  74. }
  75. void calcHeight(char *s,int n) {
  76. int i,j,k=;
  77. for(i=;i<=n;i++)rk[sa[i]]=i;
  78. for(i=;i<n;i++){
  79. if(k)k--; // h[i]>=h[i-1]-1
  80. j=sa[rk[i]-]; // suffix(j)排名在suffix(i)前一位
  81. while(s[i+k]==s[j+k])k++; // 暴力计算lcp
  82. height[rk[i]]=k;
  83. }
  84. sum[]=;
  85. for (int i=;i<=n;i++) sum[i]=sum[i-]+n-sa[i]-height[i];
  86. }
  87. int lcp(int a,int b,int len) {
  88. if (a==b) return len-a;
  89. int ra=rk[a],rb=rk[b];
  90. if (ra>rb) swap(ra,rb);
  91. return queryST(ra+,rb);
  92. }
  93. int st[N][];
  94. void initST(int n) {
  95. for (int i=;i<=n;i++)
  96. st[i][]=height[i];
  97. for (int j=;(<<j)<=n;j++) {
  98. int k=<<(j-);
  99. for (int i=; i+k<=n; i++)
  100. st[i][j]=min(st[i][j-],st[i+k][j-]);
  101. }
  102. }
  103. int queryST(int a,int b) {
  104. if (a>b) swap(a,b);
  105. int dis=b-a+;
  106. int k=log((double)dis)/log(2.0);
  107. return min(st[a][k],st[b-(<<k)+][k]);
  108. }
  109. void solve(int &l,int &r,long long k,int n) {
  110. if (k<||k>sum[n]) {
  111. l=;r=;
  112. return;
  113. }
  114. int t=lower_bound(sum,sum+n+,k)-sum;
  115. assert(t>=&&t<=n);
  116. long long now=sum[t-];
  117. int need=k-now;
  118. l=sa[t],r=sa[t]+height[t]+need-;
  119. int len=r-l+;
  120. int le=t,ri=n,ret=l;
  121. while (le<=ri) {
  122. int mid=(le+ri)/;
  123. if (lcp(sa[mid],l,n)>=len) {
  124. le=mid+;
  125. ret=mid;
  126. } else ri=mid-;
  127. }
  128. l=rmq.query(t,ret);
  129. l++;
  130. r=l+len-;
  131. }
  132. }suf;
  133.  
  134. int main () {
  135. while (scanf("%s",s)!=EOF) {
  136. int n=strlen(s);
  137. suf.calcSA(s,n+,);
  138. suf.calcHeight(s,n);
  139. suf.initST(n);
  140. rmq.setMin();
  141. rmq.init(n,suf.sa);
  142. int Q;
  143. scanf("%d",&Q);
  144. int l=,r=; //int cnt=0;
  145. while (Q--) {
  146. long long k;
  147. scanf("%I64d",&k);
  148. k^=(l^r);
  149. k++;
  150. //k=++cnt;
  151. suf.solve(l,r,k,n);
  152. printf("%d %d\n",l,r);
  153. }
  154. }
  155. return ;
  156. }

HDU 5008 求第k小子串的更多相关文章

  1. SPOJ SUBLEX 求第k小子串

    题目大意: 对于一个给定字符串,找到其所有不同的子串中排第k小的子串 先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N] 对于每个节点记录一个sc ...

  2. BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...

  3. hdu 4217 Data Structure? 树状数组求第K小

    Data Structure? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  4. 「BZOJ3998」[TJOI2015] 弦论(第K小子串)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3998 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input ...

  5. [TJOI2015]弦论(第k小子串)

    题意: 对于一个给定的长度为n的字符串,求出它的第k小子串. 有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个. 题解: 首先,因为t的原因,后缀数组较难实现, ...

  6. 树状数组求第k小的元素

    int find_kth(int k) { int ans = 0,cnt = 0; for (int i = 20;i >= 0;i--) //这里的20适当的取值,与MAX_VAL有关,一般 ...

  7. 算法导论学习之线性时间求第k小元素+堆思想求前k大元素

    对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...

  8. 求第k小的数

    题目链接:第k个数 题意:求n个数中第k小的数 题解: //由快速排序算法演变而来的快速选择算法 #include<iostream> using namespace std; const ...

  9. *HDU2852 树状数组(求第K小的数)

    KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

随机推荐

  1. C#知识整理笔记

    这里简单介绍了一些常用的属性,以及一些术语的解释和举例说明,不太全面,希望读者多多补充. 1.重载:函数名相同,参数的个数或参数类型不同; public void MyDog(string s); p ...

  2. KoaHub.JS用于Node.js的可移植Unix shell命令程序代码

    shelljs Portable Unix shell commands for Node.js ShellJS - Unix shell commands for Node.js     Shell ...

  3. NSPredicate 查询/搜索

    IOS NSPredicate 查询.搜索   简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 最常用到的函数 + (NSP ...

  4. Effective Modern C++ Item 37:确保std::thread在销毁时是unjoinable的

    下面这段代码,如果调用func,按照C++的标准,程序会被终止(std::terminate) void func() { std::thread t([] { std::chrono::micros ...

  5. 实现在easyui中的datagrid,点击某一列的列头弹出combobox下拉框

    easyUI  datagrid在列头加下拉框,实现对列内容的筛选. 代码: onLoadSuccess: function (data) {//Fires when data is loaded s ...

  6. CentOS7搭建Confluence Wiki

    前言 在艾佳生活实习时,有三款团队协作系统特别喜欢:Wiki.Jira和Jenkins.对于Jenkins的搭建,之前<自动部署工具Jenkins>有过记录.这次,搭建一个Wiki,作为知 ...

  7. download 下载文件 IE兼容性处理

    根据CANIUSE(http://caniuse.com/#search=download)download兼容性如下图所示: 如上图所示,IE浏览器是不支持的. 1.测试代码: <!docty ...

  8. 000 Python之禅

    The Zen of Python, by Tim Peters Beautiful is better than ugly.Explicit is better than implicit.Simp ...

  9. GitHub中最强大的iOS Notifications和AlertView框架,没有之一!

    FFToast是一个非常强大的iOS message notifications和AlertView扩展.它可以很容易实现从屏幕顶部.屏幕底部和屏幕中间弹出一个通知.你可以很容易的自定义弹出的View ...

  10. iOS开发之UITableView及cell重用

    1.UITanleview有的两种风格 一种是Plain,一种是Grouped,可以从这里设置风格: 他们样式分别如下: Plain: Grouped: 2.tableView展示数据的过程: (1) ...