3998: [TJOI2015]弦论

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 2627  Solved: 881

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

Source

【分析】

  建SAM,然后跑。

  right数组要按照拓扑序来求啊!!!!

  然后累计儿子的和的时候也要用拓扑序。

  具体拓扑序:

  

for(int i=1;i<=tot;i++) v[t[i].step]++;
for(int i=1;i<=tot;i++) v[i]+=v[i-1];
for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;

  类似后缀数组那里的了。

  T=0,就right一开始都为1;T=1,就用right数组。

  空串算一个串,一开始k++。

  当然后缀数组也是可以的。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 500010 struct node
{
int pre,last,son[],step;
}t[Maxn*];
int rt[Maxn*],sm0[*Maxn],sm1[*Maxn];
int v[*Maxn],q[*Maxn]; struct sam
{
int last,tot;
void extend(int k)
{
int np=++tot,p=last;
t[np].step=t[last].step+;
rt[np]=;
while(p&&!t[p].son[k])
{
t[p].son[k]=np;
p=t[p].pre;
}
if(!p) t[np].pre=;
else
{
int q=t[p].son[k];
if(t[q].step==t[p].step+) t[np].pre=q;
else
{
int nq=++tot;
memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
t[nq].step=t[p].step+;
t[nq].pre=t[q].pre;
t[q].pre=t[np].pre=nq;
while(p&&t[p].son[k]==q)
{
t[p].son[k]=nq;
p=t[p].pre;
}
}
}
last=np;
}
void init()
{
for(int i=;i<=tot;i++) v[t[i].step]++;
for(int i=;i<=tot;i++) v[i]+=v[i-];
for(int i=tot;i>=;i--) q[v[t[i].step]--]=i; // for(int i=1;i<=tot;i++) rt[i]=1;
// for(int i=tot;i>=1;i--) rt[t[i].pre]+=rt[i];
// rt[1]=1;
for(int i=tot;i>=;i--)
{
int nw=q[i];
rt[t[nw].pre]+=rt[nw];
}rt[]=; for(int i=tot;i>=;i--)
{
int nw=q[i];
sm0[nw]=;sm1[nw]=rt[nw];
for(int j=;j<=;j++) if(t[nw].son[j])
{
sm0[nw]+=sm0[t[nw].son[j]];
sm1[nw]+=sm1[t[nw].son[j]];
}
}
}
void ffind(int opt,int k)
{
int sm,nw=;
k++;
while()
{
sm=opt?rt[nw]:;
for(int i=;i<=;i++) if(t[nw].son[i])
{
int ss=sm;
if(!opt) sm+=sm0[t[nw].son[i]];
else sm+=sm1[t[nw].son[i]];
if(sm>=k) {k-=ss;printf("%c",'a'+i-);nw=t[nw].son[i];break;}
}
if(!opt&&k==) break;
if(opt&&k<=rt[nw]) break;
}
printf("\n");
}
}sam; char s[Maxn]; int main()
{
scanf("%s",s);
int l=strlen(s);
sam.last=sam.tot=;
for(int i=;i<l;i++) sam.extend(s[i]-'a'+);
sam.init();
int opt,k;
scanf("%d%d",&opt,&k);
if(!opt&&k+>sm0[]) printf("-1\n");
else if(opt&&k+rt[]>sm1[]) printf("-1\n");
else sam.ffind(opt,k);
return ;
}

2017-04-17 13:59:36

  

【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )的更多相关文章

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

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

  2. luogu P3975 [TJOI2015]弦论 SAM

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

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

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

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

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

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

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

  6. 题解-TJOI2015 弦论

    TJOI2015 弦论 字符串 \(s\) 和 \(t\) 和 \(k\).如果 \(t=0\),不同位置的相同子串算 \(1\) 个:如果 \(t=1\),不同位置的相同子串算多个.求 \(k\) ...

  7. Luogu P3975 [TJOI2015]弦论

    题目链接 \(Click\) \(Here\) 题目大意: 重复子串不算的第\(k\)大子串 重复子串计入的第\(k\)大子串 写法:后缀自动机. 和\(OI\) \(Wiki\)上介绍的写法不太一样 ...

  8. 洛谷 P3975 [TJOI2015]弦论 解题报告

    P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...

  9. BZOJ_3998_[TJOI2015]弦论_后缀自动机

    BZOJ_3998_[TJOI2015]弦论_后缀自动机 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行 ...

随机推荐

  1. 无聊js画了个菱形

    function repeat(str, count) { return count < 0 ? '' : (new Array(count)).join(str); } function di ...

  2. [oracle]centos 7 安装oracle

    换了好几个系统终于还是利用centos安装oralce成功了,这里我也参考了网上的好多资料以及oracle的官方文档 1.下载oracle,我这里选择的是11gr2版本,下载下来后有两个文件,利用un ...

  3. HTTP/2.0 简单总结(转载)

    HTTP/2.0 简单总结(转载于https://linjunzhu.github.io/blog/2016/03/10/http2-zongjie/) 如何使用上 HTTP/2.0 需要浏览器的支持 ...

  4. Metasploit 进阶

    本文是"T00LS Metasploit(第二季)"的文档版,是个人在观看视频动手操作的一个记录,仅供学习.文中会介绍Metasploit的一些基本使用:主要包括远程代码执行.MI ...

  5. HDU 1034 Candy Sharing Game (模拟)

    题目链接 Problem Description A number of students sit in a circle facing their teacher in the center. Ea ...

  6. VC连接access

    (1)首先拷贝 c:\program files\common files\system\ado\ 目录中的 msado15.dll 文件到项目中. (2)在VC中加入DLL,具体方法如下: (3)创 ...

  7. php遍历路径——php经典实例

    php遍历路径——php经典实例 代码: <html> <head> <title>遍历目录</title> <meta charset=&quo ...

  8. HMM的概述(五个基本元素、两个假设、三个解决的问题)

    一.五个基本元素 HMM是个五元组 λ =( S, O , π ,A,B) S:状态值集合,O:观察值集合,π:初始化概率,A:状态转移概率矩阵,B:给定状态下,观察值概率矩阵   二.两个假设 HM ...

  9. PEB及LDR链

    PEB地址的取得在NT内核系统中fs寄存器指向TEB结构,TEB+0x30处指向PEB结构,PEB+0x0c处指向PEB_LDR_DATA结构,PEB_LDR_DATA+0x1c处存放一些指向动态链接 ...

  10. openjudge-NOI 2.6基本算法之动态规划 专题题解目录

    1.1759 最长上升子序列 2.1768 最大子矩阵 3.1775 采药 4.1808 公共子序列 5.1944 吃糖果 6.1996 登山 7.2000 最长公共子上升序列 8.2718 移动路线 ...