题链:

http://www.spoj.com/problems/SUBLEX/
题解:

后缀自动机。
首先,因为相同的子串都被存在了自动机的同一个状态里面,所以这就很自然的避免了重复子串的问题。
然后考虑自动机里面的转移trans,发现其构成了一个DAG,且从一个状态出发,DFS下去就可以得到所有的不重复的串;
所以我们按照拓扑序对状态排序,然后DP计算出从每个状态出发可以到达多少个子串。
转移方程:$dp[p]=\sum_{trans(p,*)=q,q!=0}dp[q]+1$
然后对于每个输入的k,在自动机里面配合dp数组去dfs就好。

代码:

  1. #include<bits/stdc++.h>
  2. #define MAXN 90005
  3. #define ll long long
  4. using namespace std;
  5. ll cnt[MAXN*3];
  6. struct SAM{
  7. int size,last;
  8. int maxs[MAXN*3],trans[MAXN*3][26],parent[MAXN*3];
  9. int Newnode(int a,int b){
  10. ++size; maxs[size]=a;
  11. memcpy(trans[size],trans[b],sizeof(trans[b]));
  12. return size;
  13. }
  14. void Extend(int x){
  15. static int p,np,q,nq;
  16. p=last; last=np=Newnode(maxs[p]+1,0);
  17. for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
  18. if(!p) parent[np]=1;
  19. else{
  20. q=trans[p][x];
  21. if(maxs[p]+1!=maxs[q]){
  22. nq=Newnode(maxs[p]+1,q);
  23. parent[nq]=parent[q];
  24. parent[q]=parent[np]=nq;
  25. for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
  26. }
  27. else parent[np]=q;
  28. }
  29. }
  30. void Build(char *S){
  31. memset(trans[0],0,sizeof(trans[0]));
  32. size=0; last=Newnode(0,0);
  33. for(int i=0;S[i];i++) Extend(S[i]-'a');
  34. }
  35. }SUF;
  36. void DP(){
  37. static int in[MAXN*3],A[MAXN*3],ant,q;
  38. queue<int>Q;
  39. for(int p=1;p<=SUF.size;p++)
  40. for(int c=0;c<26;c++){
  41. q=SUF.trans[p][c]; if(!q) continue;
  42. in[q]++;
  43. }
  44. Q.push(1);
  45. while(!Q.empty()){
  46. int p=Q.front(); Q.pop(); A[++ant]=p;
  47. for(int c=0;c<26;c++){
  48. q=SUF.trans[p][c]; if(!q) continue;
  49. in[q]--; if(!in[q]) Q.push(q);
  50. }
  51. }
  52. for(int i=ant,p;i;i--){
  53. p=A[i]; cnt[p]=(p==1?0:1);
  54. for(int c=0;c<26;c++){
  55. q=SUF.trans[p][c]; if(!q) continue;
  56. cnt[p]+=cnt[q];
  57. }
  58. }
  59. // printf("%lld\n",cnt[1]);
  60. }
  61. void dfs(int p,int k,char from){
  62. static int i,q;
  63. static char ans[MAXN];
  64. if(p==1) i=0; else k--,ans[i++]=from;
  65. if(!k) return (void)(ans[i]=0,puts(ans));
  66. for(int c=0;c<26;c++){
  67. q=SUF.trans[p][c]; if(!q) continue;
  68. if(k<=cnt[q]){dfs(q,k,'a'+c); break;}
  69. k-=cnt[q];
  70. }
  71. }
  72. int main(){
  73. static char S[MAXN];
  74. scanf("%s",S);
  75. SUF.Build(S);
  76. DP();
  77. int Q,K; scanf("%d",&Q);
  78. while(Q--){
  79. scanf("%d",&K);
  80. dfs(1,K,0);
  81. }
  82. return 0;
  83. }

  

●SPOJ 7258 Lexicographical Substring Search的更多相关文章

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

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

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

    [题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...

  3. SPOJ 7258 Lexicographical Substring Search

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

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

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

  5. SPOJ SUBLEX 7258. Lexicographical Substring Search

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

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

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

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

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

  8. SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

    题目传送门 传送门I 传送门II 题目大意 给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它. 考虑后缀Trie.依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] ...

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

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

随机推荐

  1. 第一次作业:我与CS的缘分

    "既然选择了远方,便只顾风雨兼程"   --汪国真 一.结缘计算机 1.1初识计算机 当第一次看到这个作业题目的时候,我的思虑不禁回到了小时候那个对这个世界的一切充满兴趣的纯真年代 ...

  2. Beta冲刺随笔集合

    Beta冲刺随笔集合 项目Beta预备 Beta冲刺第一天 Beta冲刺第二天 Beta冲刺第三天 Beta冲刺第四天 Beta冲刺第五天 Beta冲刺第六天 Beta冲刺第七天 用户调查报告 Bet ...

  3. 冲刺NO.7

    Alpha冲刺第七天 站立式会议 项目进展 前期数据库设计所遗留的问题在今天得到了部分的解决,对物资管理所需要的数据内容进行了细化,但并未开始编写物资相关模块,主要精力还是放在项目的核心功能(信用管理 ...

  4. 2018c语言第1次作业

    6-1 计算两数的和与差 1.设计思路 (1)主要描述题目算法 第一步:把两个数的加减法分别赋给psum和pdiff. 第二步:通过psum和pdiff的地址把值传回主函数. (2)流程图.(无) 2 ...

  5. Flask-uploads 简单使用

    pip install flask-uploads#先导入次此处需要用到的库: from flask_uploads import UploadSet, IMAGES, configure_uploa ...

  6. map的infowindow的show事件(ArcGIS API for JS)

  7. mysql数据库的三范式的设计与理解

    一般的数据库设计都需要满足三范式,这是最基本的要求的,最高达到6NF,但是一般情况下3NF达到了就可以 一:1NF一范式的理解: 1NF是关系型数据库中的最基本要求,就是要求记录的属性是原子性,不可分 ...

  8. Codeforces Round #436 (Div. 2) D. Make a Permutation!

    http://codeforces.com/contest/864/problem/D 题意: 给出n和n个数(ai <= n),要求改变其中某些数,使得这n个数为1到n的一个排列,首先保证修改 ...

  9. Spring学习(1)——快速入门

    认识 Spring 框架 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP( ...

  10. require.js按需加载使用简介

    一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...