我们分成两种情况来分析这个问题:t=0和t=1

t=1时,每一个子串出现的次数就是他在parent树上所在子树内前缀节点的个数,这一点我们已经说的很清楚了

利用SAM有向无环的性质,我们可以在parent树上统计完之后在后缀自动机上dfs,对每个点累计以他为开头的所有子串的总数

然后在查询的时候直接在SAM上跑,如果以当前点为开头的子串总数小于k,则将k减去这个总数后向他的兄弟节点查询,否则输出这个节点的字符,然后向他的子节点上查询,直到k小于当前点对应子串出现次数即说明输出的答案已满足要求

t=0时,由于只区分字典序,所以每一个节点都是一个子串,字典序相同的子串不会被重复统计(这利用了后缀自动机可以不重不漏地识别原串的每个子串的优秀性质)

剩余操作同上:在后缀自动机上dfs,然后再查询

代码:

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #include <iostream>
  6. #include <algorithm>
  7. #include <queue>
  8. #include <stack>
  9. using namespace std;
  10. char ch[500005];
  11. int T,k,n;
  12. struct SAM
  13. {
  14. int tranc[27];
  15. int endpos;
  16. int len;
  17. int pre;
  18. }s[1000005];
  19. struct Edge
  20. {
  21. int next;
  22. int to;
  23. }edge[1000005];
  24. int head[1000005];
  25. int val[1000005];
  26. int sum[1000005];
  27. int cnt=1;
  28. int las,siz;
  29. void init()
  30. {
  31. memset(head,-1,sizeof(head));
  32. cnt=1;
  33. }
  34. void add(int l,int r)
  35. {
  36. edge[cnt].next=head[l];
  37. edge[cnt].to=r;
  38. head[l]=cnt++;
  39. }
  40. void ins(int c)
  41. {
  42. int nwp=++siz;
  43. s[nwp].len=s[las].len+1;
  44. s[nwp].endpos=1;
  45. int lsp;
  46. for(lsp=las;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)s[lsp].tranc[c]=nwp;
  47. if(!lsp)
  48. {
  49. s[nwp].pre=1;
  50. }else
  51. {
  52. int lsq=s[lsp].tranc[c];
  53. if(s[lsq].len==s[lsp].len+1)
  54. {
  55. s[nwp].pre=lsq;
  56. }else
  57. {
  58. int nwq=++siz;
  59. s[nwq]=s[lsq];
  60. s[nwq].endpos=0;
  61. s[nwq].len=s[lsp].len+1;
  62. s[lsq].pre=s[nwp].pre=nwq;
  63. while(s[lsp].tranc[c]==lsq)
  64. {
  65. s[lsp].tranc[c]=nwq;
  66. lsp=s[lsp].pre;
  67. }
  68. }
  69. }
  70. las=nwp;
  71. }
  72. void buildtree()
  73. {
  74. init();
  75. for(int i=2;i<=siz;i++)add(s[i].pre,i);
  76. }
  77. void dfs(int x)
  78. {
  79. if(T)val[x]=s[x].endpos;
  80. else val[x]=1;
  81. for(int i=head[x];i!=-1;i=edge[i].next)
  82. {
  83. int to=edge[i].to;
  84. dfs(to);
  85. if(T)val[x]+=val[to];
  86. }
  87. }
  88. void redfs(int x)
  89. {
  90. sum[x]=val[x];
  91. for(int i=1;i<=26;i++)
  92. {
  93. int to=s[x].tranc[i];
  94. if(!to)continue;
  95. if(!sum[to])redfs(to);
  96. sum[x]+=sum[to];
  97. }
  98. }
  99. void qdfs(int x)
  100. {
  101. if(k<=val[x])return;
  102. k-=val[x];
  103. for(int i=1;i<=26;i++)
  104. {
  105. int to=s[x].tranc[i];
  106. if(!to)continue;
  107. if(k<=sum[to])
  108. {
  109. printf("%c",i+'a'-1);
  110. qdfs(to);
  111. return;
  112. }else k-=sum[to];
  113. }
  114. }
  115. int main()
  116. {
  117. // freopen("data.in","r",stdin);
  118. scanf("%s",ch+1);
  119. scanf("%d%d",&T,&k);
  120. n=strlen(ch+1);
  121. las=++siz;
  122. for(int i=1;i<=n;i++)ins(ch[i]-'a'+1);
  123. buildtree();
  124. dfs(1);
  125. val[1]=0;
  126. redfs(1);
  127. if(k>sum[1])printf("-1");
  128. else qdfs(1);
  129. printf("\n");
  130. return 0;
  131. }

  

bzoj 3998的更多相关文章

  1. BZOJ 3998 [TJOI 2015] 弦论 解题报告

    这是一道后缀自动机经典题目. 对于 $t=0$ 的情况:每个节点都代表一个子串,所以我们给每个节点的 $Size$ 都记为 $1$, 对于 $t=1$ 的情况:我们只给 $last$ 节点的 $Siz ...

  2. BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2152  Solved: 716[Submit][Status] ...

  3. ●BZOJ 3998 [TJOI2015]弦论

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3998题解: 后缀自动机. 当T=0时, 由于在后缀自动机上沿着trans转移,每个串都是互不 ...

  4. 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2627  Solved: 881 Description 对于一 ...

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

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

  6. bzoj 3998 [TJOI2015]弦论——后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 相同子串算多个的话,先求好 right ,然后求一个 sm 表示走到这个点之后有几种走 ...

  7. BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...

  8. bzoj 3998 弦论 —— 后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 关于相同子串算一个还是算多个,其实就是看一种状态的 right 集合是否加上 Pare ...

  9. bzoj 3998: [TJOI2015]弦论【SA+二分||SAM】

    SA的话t==0直接预处理出每个后缀的不同串贡献二分即可,然后t==1就按字典序枚举后缀,然后跳右端点计算和当前后缀的前缀相同的子串个数,直到第k个 不过bzoj上会T #include<ios ...

  10. bzoj 3998: [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

随机推荐

  1. Msi中文件替换

    转自https://blog.csdn.net/davidhsing/article/details/9962377 ※说明:目前可以用于MSI编辑的软件很多,但是有些软件在保存时会在MSI文件中写入 ...

  2. NOT NULL constraint faile(慢就是快,少即是多)

    在学习数据库orm操作的过程中,遇到一个写不进去数据的问题 在创建数据库进行数据写入时出错,错误信息是 NOT NULL constraint faile(错误信息没有第一时间找到) 数据库,包括表都 ...

  3. fast-ai lesson1 错误处理(CNN创建)

    报错信息: name 'ConvLearner' is not defined 在最新的fast ai包中,ConvLearner已经被create_cnn取代,所以替换为下列语句就好了: learn ...

  4. [powershell]获取FCID&Port

    Get-InitiatorID Get-InitiatorPort

  5. [NOI2017]泳池

    题目描述 有一个长为\(n\),高为1001的网格,每个格子有\(p\)的概率为1,\((1-p)\)的概率0,定义一个网格的价值为极大的全一矩形,且这个矩形的底要贴着网格的底,求这个网格的价值为\( ...

  6. 野路子码农系列(1) 创建Web API

    新工作正式开始了2天,由于客户暂时还没交接数据过来,暂时无事可做.恰逢政佬给某超市做的商品图像识别的项目客户催收了,老板要求赶紧搞个API,于是我就想我来试试吧. 说起API,我其实是一窍不通的,我对 ...

  7. 关于 Microsoft Dynamics CRM has encountered an error 弹窗的问题

    最近用 IE 测试 CRM 网站的时候发现一个问题:时不时会弹出“Microsoft Dynamics CRM has encountered an error”的小框框,而且还不是在特定位置才会弹出 ...

  8. DirectX11--HLSL编译着色器的三种方法

    前言 本教程不考虑Effects11(FX11),而是基于原始的HLSL. 目前编译与加载着色器的方法如下: 使用Visual Studio中的HLSL编译器,随项目编译期间一同编译,并生成.cso( ...

  9. ArcGis——好好的属性表,咋就乱码了呢?

    我就瞎说一下,反正你也不懂. ——见到许多ArcGis属性表乱码的问题,也见过各种哭笑不得的解说 目录 第一节 字符编码那些事儿→字符编码简述 第二节 都是编码惹的祸→ArcGis属性表出错原因 第三 ...

  10. [算法竞赛入门经典]Message Decoding,ACM/ICPC World Finals 1991,UVa213

    Description Some message encoding schemes require that an encoded message be sent in two parts. The ...