我们先求出该字符串的\(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. IO、NIO、AIO

    一. IO 传统的IO是同步阻塞模式,数据的读取与写入会阻塞在一个线程内等待其完成. 主要面向字节流编程.(流是单向的) 二. NIO NIO支持同步非阻塞模式,在进行IO调用后,然后去 轮询调用结果 ...

  2. elasticsearch+logstash+redis+kibana 实时分析nginx日志

    1. 部署环境 2. 架构拓扑 3. nginx安装 安装在192.168.176.128服务器上 这里安装就简单粗暴了直接yum安装nginx [root@manager ~]# yum -y in ...

  3. docker启动报错iptables failed: -重建docker0网络恢复

    # docker启动报错 [root@localhost mysqlconf]# docker run -d -p 8080:8080 --link zookeeper:zookeeper -e du ...

  4. Java实现二叉树先序,中序,后序,层次遍历

    一.以下是我要解析的一个二叉树的模型形状.本文实现了以下方式的遍历: 1.用递归的方法实现了前序.中序.后序的遍历: 2.利用队列的方法实现层次遍历: 3.用堆栈的方法实现前序.中序.后序的遍历. . ...

  5. 继承extends、super、this、方法重写overiding、final、代码块_DAY08

    1:Math类的随机数(掌握) 类名调用静态方法.  包:java.lang 类:Math 方法:public static double random(): Java.lang包下的类是不用导包就可 ...

  6. iOS 8.0 bluetooth peripheral manager giving no callback for addService

    I am adding the service using: [self.peripheralManager addService:myService]; Is this method depreca ...

  7. zend studio 9.0.2 破解-注册-汉化流程

    1.运行 ZendStudio-9.0.2.msi :注意安装后不要启动: 附其下载地址:下载9.0.2版本的Zend StudioZend Studio 9.0.2下载地址:http://www.g ...

  8. 全网最详细的大数据集群环境下如何正确安装并配置多个不同版本的Cloudera Hue(图文详解)

    不多说,直接上干货! 为什么要写这么一篇博文呢? 是因为啊,对于Hue不同版本之间,其实,差异还是相对来说有点大的,具体,大家在使用的时候亲身体会就知道了,比如一些提示和界面. 全网最详细的大数据集群 ...

  9. springboot-33-使用maven打瘦包

    直接使用maven的插件打包的话, 打出来一个jar, 会非常大, 有时候在服务上传的时候会非常不方便, <plugin> <groupId>org.springframewo ...

  10. linux添加用户、修改密码

    1.在root下添加用户用 adduser 命令 # 添加用户 admin [root@flm] #sudo adduser admin 2.添加用户登录密码 # 为用户 admin 修改密码 [ro ...