spoj 7258 Lexicographical Substring Search (后缀自动机)
spoj 7258 Lexicographical Substring Search (后缀自动机)
题意:给出一个字符串,长度为90000。询问q次,每次回答一个k,求字典序第k小的子串。
解题思路:构造出sam后,类似splay求前驱的做法,不断的逼近答案。我们知道,sam里从s走到某一节点即为一个子串,所以我们在每个节点下记录一个cnt,表示该节点下,能走到的节点有多少个。那么我们在求第k小的子串时,就往下走,枚举当前节点下的26字母节点,若枚举到的节点的cnt+1>=k那么就往该节点走,并输出这条边上的字母(为什么要+1呢?因为走到这个节点就可以是一个子串)。否则k -= cnt[v] + 1 (+1的理由同上)。还有一个问题就是如何快速统计cnt了,这个留个小思考吧,其实方法前面几道题里都用到了,详细讨论请留言。
另外,这题还有个小优化,我们要把空的字母边缩掉,这个大家自己去发现了。我也因为这个T了好几发
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ; const int maxn = 90005 ; int fa[maxn<<1] , c[26][maxn<<1] , val[maxn<<1] ;
int last , tot ;
int cnt[maxn<<2] ; int max ( int a , int b ) { return a > b ? a : b ; } inline int new_node ( int step ) {
int i ;
val[++tot] = step ;
for ( i = 0 ; i < 26 ; i ++ ) c[i][tot] = 0 ;
fa[tot] = 0 ;
return tot ;
} void add ( int k ) {
int p = last , i ;
int np = new_node ( val[p] + 1 ) ;
while ( p && !c[k][p] ) c[k][p] = np , p = fa[p] ;
if ( !p ) fa[np] = 1 ;
else {
int q = c[k][p] ;
if ( val[q] == val[p] + 1 ) fa[np] = q ;
else {
int nq = new_node ( val[p] + 1 ) ;
for ( i = 0 ; i < 26 ; i ++ ) c[i][nq] = c[i][q] ;
fa[nq] = fa[q] ;
fa[np] = fa[q] = nq ;
while ( p && c[k][p] == q ) c[k][p] = nq , p = fa[p] ;
}
}
last = np ;
} void init () {
tot = 0 ;
last = new_node ( 0 ) ;
} char s[maxn] ;
int pos[maxn<<1] , ws[maxn<<1] , to[maxn<<1] ;
int main () {
scanf ( "%s" , s ) ;
init () ;
int i , len = strlen ( s ) , j ;
for ( i = 0 ; i < len ; i ++ ) add ( s[i] - 'a' ) ;
for ( i = 1 ; i <= tot ; i ++ ) ws[i] = 0 ;
for ( i = 1 ; i <= tot ; i ++ ) ws[val[i]] ++ ;
for ( i = 1 ; i <= tot ; i ++ ) ws[i] += ws[i-1] ;
for ( i = 1 ; i <= tot ; i ++ ) pos[ws[val[i]]--] = i ;
for ( i = tot ; i >= 1 ; i -- ) {
int p = pos[i] ;
int k = 0 ;
for ( j = 0 ; j < 26 ; j ++ ) {
if ( c[j][p] ) {
cnt[p] += cnt[c[j][p]] + 1 ;
c[k++][p] = c[j][p] ;
to[c[k-1][p]] = j + 'a' ;
}
}
c[k][p] = 0 ;
}
int q ;
scanf ( "%d" , &q ) ;
while ( q -- ) {
int k ;
scanf ( "%d" , &k ) ;
int p = 1 ;
while ( k > 0 ) {
i = 0 ;
while ( c[i][p] ) {
int r = c[i][p] ;
if ( cnt[r] + 1 >= k ) {
printf ( "%c" , to[r] ) ;
k -- ;
p = r ;
break ;
}
else k -= cnt[r] + 1 ;
i ++ ;
}
}
puts ( "" ) ;
}
}
spoj 7258 Lexicographical Substring Search (后缀自动机)的更多相关文章
- SPOJ 7258 Lexicographical Substring Search [后缀自动机 DP]
题意:给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个. 第一道自己做的1A的SAM啦啦啦 很简单,建SAM后跑kth就行了 也需要按val基数排序倒着 ...
- SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组
SUBLEX - Lexicographical Substring Search Little Daniel loves to play with strings! He always finds ...
- ●SPOJ 7258 Lexicographical Substring Search
题链: http://www.spoj.com/problems/SUBLEX/题解: 后缀自动机. 首先,因为相同的子串都被存在了自动机的同一个状态里面,所以这就很自然的避免了重复子串的问题. 然后 ...
- SPOJ 7258 Lexicographical Substring Search(后缀自动机)
[题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...
- SPOJ Lexicographical Substring Search 后缀自动机
给你一个字符串,然后询问它第k小的factor,坑的地方在于spoj实在是太慢了,要加各种常数优化,字符集如果不压缩一下必t.. #pragma warning(disable:4996) #incl ...
- SPOJ SUBLEX Lexicographical Substring Search - 后缀数组
题目传送门 传送门I 传送门II 题目大意 给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它. 考虑后缀Trie.依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] ...
- SPOJ 7258 Lexicographical Substring Search
Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...
- SP7258 SUBLEX - Lexicographical Substring Search - 后缀自动机,dp
给定一个字符串,求本质不同排名第k小的子串 Solution 后缀自动机上每条路径对应一个本质不同的子串 按照 TRANS 图的拓扑序,DP 计算出每个点发出多少条路径 (注意区别 TRANS 图的拓 ...
- SPOJ7258 SUBLEX - Lexicographical Substring Search(后缀自动机)
Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...
随机推荐
- OpenCV2.4.9+VS2012安装与配置
需要下载并安装Visual Studio 2012 然后在OpenCV官网下载安装OpenCV2.4.9 for Windows,网址为http://opencv.org/downloads.html ...
- WPF中PasswordBox控件无法绑定Password属性解决办法
在WPF中,默认的Password控件的Password属性是不允许为之绑定的,下面是一个解决绑定Password的方法的代码: 1.前台代码 <Window x:Class="Pas ...
- 移动网络山寨版(OpenBTS)的意义或者无意义 【1】
在美国内华达州北部,靠近加州的峡谷中,有一片平坦的沙漠,名叫黑岩沙漠(Black Rock Desert).自从1986年以来,每年夏天,在这片沙漠中,都会举办一个为期八天的狂欢节.这个狂欢节的名字叫 ...
- Android手机自带内部存储路径的获取 (转)
转自:http://my.oschina.net/liucundong/blog/288183 我有一台中兴的Android手机,型号是 ZTE U930HD,手机没有插入外置SD卡(也就是Micro ...
- OpenStreetMap(OSM) features
目录 1 Primary features 1.1 Aerialway 1.2 Aeroway 1.3 Amenity 1.3.1 Sustenance 1.3.2 Education 1.3.3 T ...
- 迪杰斯特拉(Dijkstra)算法
# include <stdio.h> # define MAX_VERTEXES //最大顶点数 # define INFINITY ;//代表∞ typedef struct {/* ...
- hdu 2768
求最大留下的观众,观众之间存在不能同时满足的关系,就是矛盾关系, 矛盾关系建边,建边是双向的所以最大匹配要/2 还有一种建图的方法:把观众分成两个集合,一个是投留下猫的,一个是投留下狗的 每个集合间没 ...
- 在asp.net中如何实现伪静态页 [转]
我在这里就不过多讨论静态页.伪静态页.动态页的长短利弊了.只是单纯的讲解如何在asp.net中如何实现伪静态页,以帮助有这方面有需求的朋友,快速解决boss派下来的任务.(拿奖金的时候,记得有我一份功 ...
- Tab Bar Controller和Navigation Controller混合使用详细教程
在IPHONE上,NAV和TAB混合使用的案例很多.但很多书籍都没详细介绍这个是怎么使用的.我也找了很久才弄清楚怎么做.现在分享给大家. 1.先建立一个Window-based Application ...
- office中回车符的问题
导入数据,有时直接把execl中的数据复制到数据表中,但如果有回车符时就会出错,这时可以用: Alt+1+0三个键来代表回车,直接替换掉