我们先求出该字符串的\(SA\)和\(Ht\)

然后分类讨论

\(T=0\)时,每次去掉\(Ht\)往后扫就行

\(T=1\)时,我们考虑\(lcp\)对答案的影响

既然用到\(lcp\),那就要用\(ST\)表维护

左端点固定时,随右端点的增大,区间\(\min\)单调不升

我们就可以用二分+限制右端点的方式统计某个后缀的前缀的贡献

循环遍历每个后缀时,由于\(Ht\)部分已经统计过对答案的贡献,就不用再计算了,从\(Ht+1\)的位置继续向后统计即可

#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std; const int MAXN=5e5+5; int ln,maxn,p,t;
int SA[MAXN],id[MAXN],rnk[MAXN],bnk[MAXN],Ht[MAXN];
char ch[MAXN];
int ST[19][MAXN],lg[MAXN]; void shel()
{
for(int i=1;i<=ln;++i) ++bnk[rnk[id[i]]];
for(int i=1;i<=maxn;++i) bnk[i]+=bnk[i-1];
for(int i=1;i<=ln;++i) SA[++bnk[rnk[id[i]]-1]]=id[i];
for(int i=0;i<=maxn;++i) bnk[i]=0;
return;
} void GetSA()
{
for(int i=1;i<=ln;++i) rnk[i]=ch[i],id[i]=i,maxn=max(maxn,rnk[i]);
shel();
for(int k=1;k<ln;k<<=1){
for(int i=1;i<=k;++i) id[i]=ln-k+i;
int ct=k;
for(int i=1;i<=ln;++i) if(SA[i]>k) id[++ct]=SA[i]-k;
shel();swap(id,rnk);rnk[SA[1]]=1;
for(int i=2;i<=ln;++i) rnk[SA[i]]=(id[SA[i]]==id[SA[i-1]]&&id[SA[i]+k]==id[SA[i-1]+k])?rnk[SA[i-1]]:rnk[SA[i-1]]+1;
if(rnk[SA[ln]]==ln) return;
maxn=rnk[SA[ln]];
}return;
} void GetHt()
{
int k=0;
for(int i=1;i<=ln;++i){
if(rnk[i]==1) continue;
if(k) --k;
int ct=SA[rnk[i]-1];
while(ct+k<=ln&&i+k<=ln&&ch[i+k]==ch[ct+k]) ++k;
Ht[rnk[i]]=k;
}return;
} int Getmi(int l,int r){int tmp=lg[r-l+1];return min(ST[tmp][l+(1<<tmp)-1],ST[tmp][r]);} void slv1()
{
for(int i=1;i<=ln;++i) lg[i]=i>>lg[i-1]+1?lg[i-1]+1:lg[i-1];
for(int i=1;i<=ln;++i) ST[0][i]=Ht[i];
for(int j=1;j<=lg[ln];++j){
int tmp=1<<j-1;
for(int i=tmp<<1;i<=ln;++i){
ST[j][i]=min(ST[j-1][i],ST[j-1][i-tmp]);
}
}for(int i=1;i<=ln;++i){
int tmp=SA[i]+Ht[i];
int ct=ln;
while(1){
if(tmp>ln) break;
if(ct==i){
if(t>ln-tmp+1){t-=ln-tmp+1;break;}
for(int j=SA[i];j<=tmp+t-1;++j) putchar(ch[j]);
return;
}int l=i,r=ct;
while(l<r){
int mid=l+r+1>>1;
if(Getmi(i+1,mid)>=tmp-SA[i]+1) l=mid;
else r=mid-1;
}ct=r;
if(t>r-i+1) t-=r-i+1;
else{
for(int j=SA[i];j<=tmp;++j) putchar(ch[j]);
return;
}++tmp;
}
}puts("-1");
return;
} void slv2()
{
int ct=1;
while(t>ln-SA[ct]-Ht[ct]+1) t-=ln-SA[ct]-Ht[ct]+1,++ct;
if(ct>ln){puts("-1");return;}
for(int i=SA[ct];i<=SA[ct]+t+Ht[ct]-1;++i) putchar(ch[i]);
puts("");
return;
} int main()
{
scanf("%s",ch+1);ln=strlen(ch+1);
GetSA();GetHt();scanf("%d%d",&p,&t);
p?slv1():slv2();
return 0;
}

[TJOI2015]弦论的更多相关文章

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

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

  2. Luogu P3975 [TJOI2015]弦论

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

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

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

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

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

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

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

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

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

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

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

  8. luogu P3975 [TJOI2015]弦论 SAM

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

  9. LGOJ3975 TJOI2015 弦论

    link:TJOI2015 弦论 题目大意: 给定一个字符串,输出在对该字符串所有的非空子串排序后第\(k\)个 另外的一个限制是\(T\):子串本质相同但位置不同算\(1\)或多个 \(|s| \l ...

  10. 题解-TJOI2015 弦论

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

随机推荐

  1. Git - 回滚与撤销

    必要的概念 当前编辑界面:工作区(workspace) "git add"命令:将改动加入到缓存区(Index) "git commit"命令:提交代码到本地库 ...

  2. java爬虫学习

    一.java爬取数据 示例:爬取网站中的所有古风网名:http://www.oicq88.com/gufeng/,并储存入数据库(mysql) jdk版本:jdk1.8 编辑器:idea 项目构建:m ...

  3. POJ 2853

    #include<iostream> #include<stdio.h> #include<vector> #include<math.h> #incl ...

  4. Python数据结构:栈 队列

    栈,队列的特性: 1.栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征 2.队列(queue)是一种具有 ...

  5. 解决 在 WINDOWS 下 同时安装 python2 python3 后 pip 错误

    再之前同时安装 python 后 只需把环境变量PATH 里面改为 PATH=C:\Python36-32\Scripts\;C:\Python36-32\;C:\Python27\;C:\Pytho ...

  6. Ruby:多线程队列(Queue)下载博客文章到本地

    Ruby:多线程下载博客文章到本地的完整代码 #encoding:utf-8 require 'net/http' require 'thread' require 'open-uri' requir ...

  7. MySQL笔记(1)---MySQL体系结构和存储引擎

    1.前言 本系列记录MYSQL数据库的一些结构和实现特点,方便查询. 2.基本概念 数据库:物理操作系统文件或者其他形式文件类型的集合.MySQL中数据库文件可以是frm.MYD.MYI.ibd结尾的 ...

  8. 利用:before和:after伪类制作CSS3 圆形按钮 含demo

    要求 必备知识 基本了解CSS语法,初步了解CSS3语法知识. 开发环境 Adobe Dreamweaver CS6 演示地址 演示地址 预览截图(抬抬你的鼠标就可以看到演示地址哦): 制作步骤: 一 ...

  9. jdk8-stream-并行流的使用

    使用jdk的stream, 可以非常方便的将串行改为并行 1, 判断是否质数 /** * 将一个stream改成简单的并行 */ @Test public void test1() { // 串行 , ...

  10. 【IT笔试面试题整理】反转链表

    [试题描述]定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点 [参考代码] 方法一: public static Link reverseLinkList(Link head) ...