弦论

Time Limit: 10 Sec  Memory Limit: 256 MB
[Submit][Status][Discuss]

Description

  对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

  第一行是一个仅由小写英文字母构成的字符串S。
  第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。
  T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

  输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

  aabc
  0 3

Sample Output

  aab

HINT

  N<=5*10^5, T<2, K<=10^9

Solution

  首先我们先构造一个后缀自动机,然后分类讨论:

  1. 如果T=0,点权为1。为什么呢?一个点有一个Right集合,一个Right集合可以表达多个子串 ,然后我们一个点 -> 另外一个点 其实不止一条边,我们每条边涵盖了一个信息,意味着 这个点->(走这条边)->到达了下一个点 通过这条边得到的那个新子串,而这多个新子串构成了一个 新的点。所以一条合法的路径,就表达了一个子串

  2. 如果T=1,点权为Right集合大小。Right集合是结束位置的合集,那么Right集合大小就表示这条路径表达的这个子串出现了多少次。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long s64; const int ONE = 2e6+; int n,T,k;
char ch[]; inline int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} struct SAM
{
int v[], q[ONE], num[ONE], size[ONE];
int a[ONE][], len[ONE], fa[ONE], New;
int last, cnt; SAM() {last = cnt = ;}
void Add(int c)
{
int x=last, New=last=++cnt;
len[New] = len[x] + ;
num[New] = ;
while(x && !a[x][c]) a[x][c] = New, x = fa[x];
if(!x) {fa[New] = ; return;} int q = a[x][c];
if(len[x] + == len[q]) fa[New] = q;
else
{
int Nq = ++cnt; len[Nq] = len[x] + ;
memcpy(a[Nq], a[q], sizeof(a[q]));
fa[Nq] = fa[q];
fa[New] = fa[q] = Nq;
while(a[x][c] == q) a[x][c] = Nq, x = fa[x];
}
} void Update()
{
for(int i=;i<=cnt;i++) v[len[i]]++;
for(int i=;i<=n;i++) v[i] += v[i-];
for(int i=cnt;i>=;i--) q[v[len[i]]--] = i; for(int i=cnt; i>=; i--)
{
int x = q[i];
if(!T) num[x] = ; else num[fa[x]] += num[x];
}
num[] = ; for(int i=cnt; i>=; i--)
{
int x = q[i];
size[x] = num[x];
for(int j=; j<=; j++)
size[x] += size[a[x][j]];
}
} void Dfs(int u,int k)
{
if(k <= num[u]) return;
k -= num[u];
for(int j=; j<=; j++)
if(a[u][j])
{
if(k > size[a[u][j]]) k -= size[a[u][j]];
else
{
printf("%c",j+'a'-);
Dfs(a[u][j], k);
return;
}
}
}
}S; int main()
{
scanf("%s",ch+); n = strlen(ch+);
T = get(); k = get();
for(int i=;i<=n;i++) S.Add(ch[i]-'a'+); S.Update(); if(k > S.size[]) printf("-1");
else S.Dfs(, k); }

最新文章

  1. asp.net LINQ数据访问技术from where select order by子句
  2. icon@font-face那些事
  3. Cassandra + Eclipse + Hadoop
  4. leetcode二分查找问题整理
  5. ubunutu_install_sublime_china
  6. BZOJ2055: 80人环游世界
  7. 屯题50AC纪念
  8. C# 知识点收集
  9. JS计算两个日期时间之差之天数不正确
  10. Java大数据应用领域及就业方向
  11. Given two binary string, return their sum (also a binary string)
  12. poj2975 Nim 胜利的方案数
  13. 如何用kaldi做孤立词识别二
  14. Ddos 分布式拒绝服务 (报告)
  15. Ruby零碎笔记
  16. 在HTML中用循环语句
  17. AltiumDesigner PCB布局布线过程与技巧
  18. Spring整合quartz2.2.3总结,quartz动态定时任务,Quartz定时任务集群配置
  19. ADOX创建ACCESS 表时,几个附加属性
  20. 改变父元素的透明度,不影响子元素的透明度—css

热门文章

  1. 一个例子说明mouseover事件与mouseenter事件的区别
  2. Java之comparable接口
  3. TCP系列30—窗口管理&流控—4、Cork算法
  4. &lt;Android&gt;资源的访问,颜色、字符串、尺寸、XML、DRAWABLES资源分使用
  5. 201621044079WEEK作业08-集合
  6. JDK各个版本比较 JDK5~JDK9
  7. [转]matlab中squeeze函数的用法,numel的用法
  8. BZOJ 1046 上升序列(LIS变形)
  9. BZOJ4871 Shoi2017摧毁“树状图”(树形dp)
  10. 协程简介-异步IO