前言:

多好的题啊!

我理论$O(nlog_2n)$的后缀数组还带个常数26,竟然跑的比$O(n)$的后缀自动机还快,全场 Rak 1?

Description

为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

Input

第一行是一个仅由小写英文字母构成的字符串s

第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

Output

输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

题解:

相信T=0,大家都会做,这是后缀数组的一个经典问题。

具体就是,每个子串都是一个后缀的前缀。

从头到尾扫,每个后缀都会有 $n-sa[i]+1-height[i]$ 个本质不同的子串,即可。

重点是T=1时,怎么用后缀数组解决?

由于我比较菜,我想了一个大暴力,一位一位的枚举!

因为我们前面的字母是确定的,那么当前面的字母一样的时候,后面一个字母一定是单调不下降的。

那我们就能二分求出这个字母最后一个的位置。

我们建一个后缀长度的前缀和,那我们就能求出以这个字母开头的子串有多少个。

当个数大于$k$时,就确定了这个字母,否则$k$减去,继续枚举下一个字母。

枚举完一位继续下一位,那我们就能把范围缩小,知道求出答案。

具体看代码……

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; int n,t,k;
long long sum[];
char s[];
struct SA{
char s[];
int tp[],rak[];
int tax[],sa[];
int n,m,height[];
void build(char str[]){
memcpy(s,str,sizeof(s));
n=strlen(s+);
build_sa(rak,tp);
build_height();
}
void sort(int a[],int b[]){
for(int i=;i<=m;i++)tax[i]=;
for(int i=;i<=n;i++)tax[a[i]]++;
for(int i=;i<=m;i++)tax[i]+=tax[i-];
for(int i=n;i>=;i--)sa[tax[a[b[i]]]--]=b[i];
}
bool comp(int r[],int a,int b,int k){
return r[a]==r[b]&&r[a+k]==r[b+k];
}
void build_sa(int a[],int b[]){
for(int i=;i<=n;i++)
m=max(m,a[i]=s[i]-'a'+),b[i]=i;
sort(a,b);
for(int p=,j=;p<n;j<<=,m=p){
p=;
for(int i=;i<=j;i++)b[++p]=n-j+i;
for(int i=;i<=n;i++)if(sa[i]>j)b[++p]=sa[i]-j;
sort(a,b);
int *t=a;a=b;b=t;
a[sa[]]=p=;
for(int i=;i<=n;i++)
a[sa[i]]=comp(b,sa[i],sa[i-],j)?p:++p;
}
for(int i=;i<=n;i++)rak[sa[i]]=i;
}
void build_height(){
for(int i=,j=;i<=n;i++){
if(j)j--;
while(s[i+j]==s[sa[rak[i]-]+j])j++;
height[rak[i]]=j;
}
}
}a; int main(){
scanf("%s%d%d",s+,&t,&k);
a.build(s);
n=strlen(s+);
if(t==){
for(int i=;i<=n;i++){
int c=n-a.sa[i]+-a.height[i];
if(k<=c){
for(int j=a.sa[i];j<=a.sa[i]+a.height[i]+k-;j++)
putchar(s[j]);
return ;
}else k-=c;
}
printf("-1");
}else{
for(int i=;i<=n;i++) //处理前缀和
sum[i]=sum[i-]+n-a.sa[i]+;
if(sum[n]<k)return printf("-1"),; //子串不够输出-1
int L=,R=n;
for(int i=;i<=n;i++){
int tmp=L;
for(int j='a';j<='z';j++){ //枚举 a~z
int l=tmp,r=R;
while(l<=r){ //二分找这个字母的最后一个位置
int mid=l+r>>;
if(s[a.sa[mid]+i-]>j)r=mid-;
else l=mid+;
}
long long t=sum[r]-sum[tmp-]-1LL*(r-tmp+)*(i-);
//现在枚举的区间有多少个子串
//减是因为减去前面枚举过得位置
if(k<=r-tmp+){
//现在要查的比现在字母的个数少,说明这个字母就是结束的位置
for(int j=a.sa[tmp];j<=a.sa[tmp]+i-;j++)
putchar(s[j]);
return ;
}
if(t>=k){ //说明这位就是这个字母,减去字母个数
L=tmp,R=r;
k-=r-tmp+;
break;
}
tmp=r+,k-=t; //不是,继续枚举
}
if(n-a.sa[L]+==i)L++; //如果下一位为空,就不用算了。
}
}
}

【TJOI2015】弦论 (后缀数组)的更多相关文章

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

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

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

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

  3. [bzoj3998][TJOI2015]弦论-后缀自动机

    Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...

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

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

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

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

  6. 【bzoj3998】[TJOI2015]弦论 后缀自动机+dp

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

  7. BZOJ 3998 [TJOI2015]弦论 ——后缀自动机

    直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...

  8. [TJOI2015]弦论(后缀自动机)

    /* 一道在树上乱搞的题目 建立出parent树来, 然后就能搞出每个节点往后能扩展出几个串, 至于位置不同算同一个的话就强制让right集合大小为1即可 然后在树上类比权值线段树找第k大26分统计一 ...

  9. BZOJ.3998.[TJOI2015]弦论(后缀自动机)

    题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...

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

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

随机推荐

  1. 问题009:java当中的关键字有哪些?在Editplus文本编辑软件中是什么颜色的?java当中的标识符有什么要求?Java中注释分为几类?

    (1) public 公共的,表示访问的权限 (2) private 私有的,表示一种访问权限 (3) class 类关键字,表示定义一个类 java中的关键字都是大写的还是小写的?小写的,在Edit ...

  2. vue-cli npm run build 打包问题 webpack@3.6

    1, vue-router 路由 有两个模式 (mode) hash (默认模式) 使用URL来模拟一个完整的URL 但是没个URL都会带上 "#/'' 支持所有浏览器 这个模式使用 red ...

  3. vue.js devtools安装

    在调试的时候chrome会提示安装vue devtools,我以为是要在chrome的程序商店直接安装,但是国内对谷歌的和谐,无法访问谷歌商店内容 官方有源代码,可以下载下来自行编译安装 官方地址:h ...

  4. 【PHP】判断变量是否为控

    1. isset功能:判断变量是否被初始化 说明:它并不会判断变量是否为空,并且可以用来判断数组中元素是否被定义过注意:当使用isset来判断数组元素是否被初始化过时,它的效率比array_key_e ...

  5. vue时时监听input输入框中 输入内容 写法

    Vue input 监听 使用 v-on:input="change" 实现即可 App.vue <template> <div> <md-field ...

  6. mysql破解密码安装与基本管理

    一.MySQL介绍 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下公司.MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是 ...

  7. Hive将SQL转化为MapReduce的过程

    Hive将SQL转化为MapReduce的过程: Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree 遍历AST Tree,抽象出查询的基本组成单元Qu ...

  8. LoadRunner11的安装和使用及其注意点(测试系统是win7)

    一.安装 LoadRunner11的下载地址:http://www.ddooo.com/softdown/61971.htm 链接标题里[loadrunner11 中文破解版]实质上下载下来是没有破解 ...

  9. FSMO

    FSMO 编辑 本词条缺少信息栏.名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! FSMO是Flexible single master operation的缩写,意思就是灵活单主机操 ...

  10. Asp.net页面生命周期详解任我行(2)-WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用

    摘要 页面类是如何结合后台文件类生成整个页面的HTML的代码和后台输出的代码输出到浏览器中呢?这就牵扯到Asp.net页面生命周期中一个很重要的概念控件树.服务器以反射的方式创建了页面类对象 内容 我 ...