题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3998
题解:

后缀自动机。
当T=0时,
由于在后缀自动机上沿着trans转移,每个串都是互不相同的,
就只需要统计出从每个状态出发,存在多少条不同的路径,即有多少个不同的子串。
这个可以拓扑排序后用DP解决。
转移: $$cnt[p]=\sum_{trans[p][*]=q,q!=0} cnt[q] + 1$$
然后配合cnt[]去dfs即可。
当T=1时,
这时考虑了相同的子串。但是不难发现,
如果沿着trans转移到了一个状态s,
那么s的Right集合大小就表示了这个串出现了多少次。
所以沿用上面T=0的做法,只是把DP转移稍稍修改一下:
转移: $$cnt[p]=\sum_{trans[p][*]=q,q!=0} cnt[q] + right[p]$$
(把+1改为+right[p即可],接下来同样是配合cnt[]去dfs。)
(本人代码跑得很慢,2333)

代码:

#include<bits/stdc++.h>
#define MAXN 500005
#define ll long long
using namespace std;
ll cnt[MAXN*3];
struct SAM{
int size;
int maxs[MAXN*3],trans[MAXN*3][26],parent[MAXN*3],right[MAXN*3];
int Newnode(int a,int b){
++size; maxs[size]=a;
memcpy(trans[size],trans[b],sizeof(trans[b]));
return size;
}
int Extend(int last,int x){
static int p,np,q,nq;
p=last; np=Newnode(maxs[p]+1,0);
for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
if(!p) parent[np]=1;
else{
q=trans[p][x];
if(maxs[p]+1!=maxs[q]){
nq=Newnode(maxs[p]+1,q);
parent[nq]=parent[q];
parent[q]=parent[np]=nq;
for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
}
else parent[np]=q;
}
return np;
}
void Build(char *S){
static int p=1,last,tmp[MAXN],order[MAXN*3],len;
memset(trans[0],0,sizeof(trans[0]));
size=0; last=Newnode(0,0); len=strlen(S);
for(int i=0;i<len;i++) last=Extend(last,S[i]-'a'); for(int i=0;i<len;i++) p=trans[p][S[i]-'a'],right[p]++;
for(int i=1;i<=size;i++) tmp[maxs[i]]++;
for(int i=1;i<=len;i++) tmp[i]+=tmp[i-1];
for(int i=1;i<=size;i++) order[tmp[maxs[i]]--]=i;
for(int i=size;i;i--) p=order[i],right[parent[p]]+=right[p];
}
void Count(int t){
static queue<int> Q;
static int in[MAXN*3],order[MAXN*3],ont;
for(int p=1;p<=size;p++)
for(int c=0;c<26;c++) if(trans[p][c])
in[trans[p][c]]++;
Q.push(1);
while(!Q.empty()){
int u=Q.front(); Q.pop(); order[++ont]=u;
for(int c=0;c<26;c++) if(trans[u][c]){
in[trans[u][c]]--;
if(!in[trans[u][c]]) Q.push(trans[u][c]);
}
}
for(int i=size,p;i;i--){
p=order[i]; cnt[p]=p==1?0:t==0?1:right[p];
for(int c=0;c<26;c++) if(trans[p][c])
cnt[p]+=cnt[trans[p][c]];
}
}
}SUF;
void DFS(int p,int k,int t,int from){
static int i;
static char ans[MAXN];
if(p==1) i=0;
else{
ans[i++]=from+'a';
k-=t==0?1:SUF.right[p];
}
if(k<=0) return (void)(ans[i]=0,puts(ans));
for(int c=0;c<26;c++){
if(k<=cnt[SUF.trans[p][c]]){
DFS(SUF.trans[p][c],k,t,c);
break;
}
k-=cnt[SUF.trans[p][c]];
}
}
int main(){
int T,K;
static char S[MAXN];
scanf("%s%d%d",S,&T,&K);
SUF.Build(S);
SUF.Count(T);
// printf("%lld\n",cnt[1]);
if(K<=cnt[1]) DFS(1,K,T,0);
else puts("-1");
return 0;
}

  

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

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

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

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

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

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

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

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

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

  5. bzoj 3998: [TJOI2015]弦论【SA+二分||SAM】

    SA的话t==0直接预处理出每个后缀的不同串贡献二分即可,然后t==1就按字典序枚举后缀,然后跳右端点计算和当前后缀的前缀相同的子串个数,直到第k个 不过bzoj上会T #include<ios ...

  6. bzoj 3998: [TJOI2015]弦论

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

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

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

  8. 【刷题】BZOJ 3998 [TJOI2015]弦论

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

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

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

随机推荐

  1. WebSocket 聊天室加自制服务器

    自动监听本地ip 占用端口9930 打开服务器 再打开页面 输入服务器监听的ip和端口 局域网可以输入内网ip 外网连接 要输入服务器的外网ip 路由器需做好映射 实现WebSocket通信功能  和 ...

  2. nyoj 孪生素数

    孪生素数问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 写一个程序,找出给出素数范围内的所有孪生素数的组数.一般来说,孪生素数就是指两个素数距离为2,近的不能再 ...

  3. slf4j 与 log4j2 基本用法

    简单的说 log4j2 是log4j2的升级版,解决了部分性能问题和部分死锁问题,其使用方式与使用配置与log4j相同. 建议使用maven依赖直接使用log4j2 <dependency> ...

  4. Python format 格式化函数

    str.format() 格式化字符串的函数 str.format(),它增强了字符串格式化的功能. 基本语法是通过 {} 和 : 来代替以前的 % format 函数可以接受不限个参数,位置可以不按 ...

  5. 原始的Ajax方法 (异步的 JavaScript 和 XML -- (Extensible Markup Language 可扩展标记语言))

    <script language="javascript" type="text/javascript"> var request = false; ...

  6. JAVA_SE基础——31.this关键字

    黑马程序员入学blog... 也算是学习笔记体会. this的通俗解释: 有一个A类,一个B方法,一个C变量,其中B和C都在类A中 this.B()就是调用A类中的B方法 this.C=1(假设C是一 ...

  7. 如何深入系统的学习一门编程语言——python自学笔记

    前言 最早接触python的时候,他并没有现在这么火,我也没把他太当回事,那时候我对python的印象就是给运维人员使用的一门很古老的语言,显然随着tensorflow(以下简称tf)的兴起,pyth ...

  8. Python学习之中文注释问题

    简单写个输入.输出,并注释 # 输入 print'100+200=',100+200 # 输入 name = raw_input() 报错了: SyntaxError: Non-ASCII chara ...

  9. UVA850【简单模拟】

    题目:解密句子.有一些被加密的句子已知一条模板翻译,判断是否可以解密,可以的话将所有句子解密. #include <stdio.h> #include<iostream> #i ...

  10. SpringBoot2.x开发案例之整合Quartz任务管理系统

    基于spring-boot 2.x + quartz 的CRUD任务管理系统,适用于中小项目. 基于spring-boot +quartz 的CRUD任务管理系统: https://gitee.com ...