弦论

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); }

【BZOJ3998】弦论 [SAM]的更多相关文章

  1. BZOJ3998 弦论 【SAM】k小子串

    BZOJ3998 弦论 给一个字符串,问其第\(K\)小字串是什么 两种形式 1.不同起始位置的相同串只算一次 2.不同起始位置的相同串各算一次 首先建\(SAM\) 所有串的数量就是\(SAM\)中 ...

  2. bzoj3998: [TJOI2015]弦论(SAM+dfs)

    3998: [TJOI2015]弦论 题目:传送门 题解: SAM的入门题目(很好的复习了SAM并加强Right集合的使用) 其实对于第K小的字符串直接从root开始一通DFS就好,因为son边是直接 ...

  3. BZOJ3998:[TJOI2015]弦论(SAM)

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

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

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

  5. luogu P3975 [TJOI2015]弦论 SAM

    luogu P3975 [TJOI2015]弦论 链接 bzoj 思路 建出sam. 子串算多个的,统计preant tree的子树大小,否则就是大小为1 然后再统计sam的节点能走到多少串. 然后就 ...

  6. 弦论(tjoi2015,bzoj3998)(sam(后缀自动机))

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

  7. bzoj3998 [TJOI2015]弦论(SAM)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3998 [题意] 询问排名第k的子串是谁,0代表相同子串不同位置算作相同,1代表相同子串 ...

  8. 【BZOJ3998】弦论(后缀自动机)

    [BZOJ3998]弦论(后缀自动机) 题面 BZOJ 题解 这题应该很简单 构建出\(SAM\)后 求出每个点往后还能构建出几个串 按照拓扑序\(dp\)一些就好了 然后就是第\(k\)大,随便搞一 ...

  9. 【BZOJ3998】[TJOI2015]弦论 后缀自动机

    [BZOJ3998][TJOI2015]弦论 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T ...

随机推荐

  1. Swift-可选值(Optional)讲解

    前提:Swift中有规定:对象中的任何属性在创建时,都必须要有明确的初始化值 1.定义可选类型 方式一:常规方式(不常用) var name : Optional<String> = ni ...

  2. Coredump及调试

    1.查看是否打开了coredump lybxin@Inspiron:~/MyRes/miscellany/test/01_coredump$ulimit -c  #这里可以看到ulimit限制core ...

  3. <Android>tab选项卡

    1.继承TabActivity实现 a)         在布局文件中使用FrameLayout列出Tab组件及Tab中的内容组件 b)        Activity要继承TabActivity c ...

  4. Token安全

    token相对安全加密算法 http://blog.csdn.net/q8649912/article/details/52370565 关于文章的理解 1 sessionid 这个名词应该理解为:一 ...

  5. 3dContactPointAnnotationTool开发日志(十九)

      增加了输出接触点信息到文件功能.

  6. zabbix概念

    Zabbix是一个企业级的.开源的.分布式监控解决方案. Zabbix可以监控网络和服务的监控状况. Zabbix利用灵活的告警机制,允许用户对事件发送基于Email的告警. 这样可以保证快速的对问题 ...

  7. sql server 带输入输出参数的分页存储过程(效率最高)

    create procedure proc_page_withtopmax( @pageIndex int,--页索引 @pageSize int,--每页显示数 @pageCount int out ...

  8. [C/C++] char data[0](柔性数组)

    转自:http://blog.csdn.net/yby4769250/article/details/7294696 在标准C和C++中0长数组如charArray[0]是不允许使用的,因为这从语义逻 ...

  9. DELPHI enablecontrols,disablecontrols函数

    DisableControls方法是在程序修改或后台有刷新记录的时候切断数据组件,如TTABLE.ADOQUERY等等与组件数据源的联系.如果没有切断,数据源中只要一有数据的改动,尤其是批量改动的话, ...

  10. BZOJ 2303 方格染色(带权并查集)

    要使得每个2*2的矩形有奇数个红色,如果我们把红色记为1,蓝色记为0,那么我们得到了这2*2的矩形里的数字异或和为1. 对于每个方格则有a(i,j)^a(i-1,j)^a(i,j-1)^a(i-1,j ...