题链:

http://www.spoj.com/problems/SUBLEX/
题解:

后缀自动机。
首先,因为相同的子串都被存在了自动机的同一个状态里面,所以这就很自然的避免了重复子串的问题。
然后考虑自动机里面的转移trans,发现其构成了一个DAG,且从一个状态出发,DFS下去就可以得到所有的不重复的串;
所以我们按照拓扑序对状态排序,然后DP计算出从每个状态出发可以到达多少个子串。
转移方程:$dp[p]=\sum_{trans(p,*)=q,q!=0}dp[q]+1$
然后对于每个输入的k,在自动机里面配合dp数组去dfs就好。

代码:

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

  

●SPOJ 7258 Lexicographical Substring Search的更多相关文章

  1. spoj 7258 Lexicographical Substring Search (后缀自动机)

    spoj 7258 Lexicographical Substring Search (后缀自动机) 题意:给出一个字符串,长度为90000.询问q次,每次回答一个k,求字典序第k小的子串. 解题思路 ...

  2. SPOJ 7258 Lexicographical Substring Search(后缀自动机)

    [题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...

  3. SPOJ 7258 Lexicographical Substring Search

    Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...

  4. SPOJ 7258 Lexicographical Substring Search [后缀自动机 DP]

    题意:给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个. 第一道自己做的1A的SAM啦啦啦 很简单,建SAM后跑kth就行了 也需要按val基数排序倒着 ...

  5. SPOJ SUBLEX 7258. Lexicographical Substring Search

    看起来像是普通的SAM+dfs...但SPOJ太慢了......倒腾了一个晚上不是WA 就是RE ..... 最后换SA写了...... Lexicographical Substring Searc ...

  6. SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组

    SUBLEX - Lexicographical Substring Search Little Daniel loves to play with strings! He always finds ...

  7. 【SPOJ】7258. Lexicographical Substring Search(后缀自动机)

    http://www.spoj.com/problems/SUBLEX/ 后缀自动机系列完成QAQ...撒花..明天or今晚写个小结? 首先得知道:后缀自动机中,root出发到任意一个状态的路径对应一 ...

  8. SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

    题目传送门 传送门I 传送门II 题目大意 给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它. 考虑后缀Trie.依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] ...

  9. spoj SUBLEX (Lexicographical Substring Search) RE的欢迎来看看

    SPOJ.com - Problem SUBLEX 这么裸的一个SAM,放在了死破OJ上面就是个坑. 注意用SAM做的时候输出要用一个数组存下来,然后再puts,不然一个一个字符输出会更慢. 还有一个 ...

随机推荐

  1. C语言第二次博客作业——分支结构

    一.PTA实验作业 题目1:计算分段函数 1.实验代码 #include<stdio.h> #include<math.h> int main(void) { double x ...

  2. C++ STL常用容器基本用法汇总

    1.vector 包含头文件#include<vector> 使用命名域using namespace std 定义元素类型为T的vector vector<T> vec 增: ...

  3. 201621123054 《Java程序设计》第六周实验总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 1.2 可选:使用常规方法总结其他上课内容. 2 ...

  4. python 单向链表实现

    单链表的操作 is_empty() 链表是否为空 length() 链表长度 travel() 遍历整个链表 add(item) 链表头部添加元素 append(item) 链表尾部添加元素 inse ...

  5. codevs 1291 火车线路

    http://codevs.cn/problem/1291/ 题目描述 Description 某列火车行使在C个城市之间(出发的城市编号为1,结束达到的城市的编号为C),假设该列火车有S个座位,现在 ...

  6. hdu 5274 Dylans loves tree

    Dylans loves tree http://acm.hdu.edu.cn/showproblem.php?pid=5274 Time Limit: 2000/1000 MS (Java/Othe ...

  7. Linux基础常用命令

    Linux 下命令有很多,并且很多命令用法又有不同的选项,这里介绍一些常用的最基本的Linux命令的用法,希望给大家留下便利之处. 1.cd 切换目录.例如 cd /home 可切换到home目录,  ...

  8. python端口扫描用多线程+线程安全的队列+Thread类实现

    用线程安全的队列Queue实现扫描端口数据存储 用多线程扫描端口 用Thread类实现程序组织 #coding:utf-8 import sys import socket import sys im ...

  9. ajax和jquery使用技巧

    1.使用ajax的方法的时候可以使用u方法来获取连接,这样更加安全:alert弹窗的时候需要单引号双引号火狐浏览器会报错!

  10. markdown最基本的几种语法

    1.标题 # 相当于<h1></h1> ## 相当于<h2></h2> ### 相当于<h3></h3> #### 相当于< ...