题链:

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. B-day5

    1.昨天的困难,今天解决的进度,以及明天要做的事情 昨天的困难:昨天虽然完成了风险数据的图表统计,但是界面风格仍然不太满意,还在抓紧调试中:还有登录页的背景图,在想应该如何设计, 什么样的风格才好. ...

  2. C语言--第一周作业(更改)

    *********************学习总结********************* 1.所用词典: 2.Git截图: *********************遇到的问题和解决方法***** ...

  3. io多路复用(二)

    服务端 import socket sk1 = socket.socket() sk1.bind(('127.0.0.1',8001,)) sk1.listen() inputs = [sk1,] i ...

  4. codevs 1283 等差子序列

    http://codevs.cn/problem/1283/ 题目描述 Description 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4& ...

  5. 如何书写高效的css样式

    如何书写高效的css样式? 有以下四个关键要素: 1.高效的css 2.可维护的css 3.组件化的css 4.hack-free  css 书写高效的css: 1.使用外联样式替代行间样式或内嵌样式 ...

  6. EasyUI 中datagrid 分页。

    注释:datagrid分页搞了好几天才完全搞好,网上没完全的资料.明天晚上贴代码. 睡觉.

  7. C# 使用 GDI+ 画图

    最近做一个微信公众号服务,有一些简单的图片处理功能.主要就是用户在页面操作,前端做一些立刻显示的效果,然后提交保存时后端真正修改原图. 我们的后端是 ASP.NET,也就是 C# 语言了,C# 本身处 ...

  8. Spring入门(3-1)Spring的标签命名空间

    1.标签命名空间声明: 2.标签命名空间使用 标签默认的命名空间是 security:,可以不用带 security:,直接写标签,如: <http  <authentication-ma ...

  9. 使用 Angular CLI 和 Webpack 分析包尺寸

    使用 Angular CLI 和 Webpack 分析包尺寸 对于 Web app 来说,高性能总是最高优先级,对于 Angular 也不例外.但是随着应用复杂度的不断增长,我们如何才能知道哪些内容打 ...

  10. MongoDB系列四(索引).

    一.索引简介 再来老生常谈一番,什么是索引呢?数据库索引与书籍的索引类似.有了索引就不需要翻整本书,数据库可以直接在索引中查找,在索引中找到条目以后,就可以直接跳转到目标文档的位置,这能使查找速度提高 ...