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 ...
随机推荐
- DenyHosts 安装及配置详解
DenyHosts是Python语言写的一个程序,它会分析sshd的日志文件(/var/log/secure),当发现重 复的攻击时就会记录IP到/etc/hosts.deny文件,从而达到自动屏IP ...
- qt介绍
http://www.oschina.net/p/qt Qt 是一个跨平台的C++图形用户界面应用程序框架.它提供给开发者建立图形用户界面所需的功能,广泛用于开发GUI程序,也可用于开发非GUI程序. ...
- Hibernate 、多表关联映射 - 一对一关系映射(one- to-one)
hibernate.cfg.xml: <hibernate-configuration> <session-factory name="sessionFactory&quo ...
- bind新发现
function foo(a,b){ this.val = a+b; } var bar = foo.bind(null, 'p1'); var baz = new bar('p2'); consol ...
- jQuery特效 隔行变色
1.通过使用onmouseover onmouseout方法 2.变色使用background-color(css)属性 3.变色的标签是td(tr仅仅能使用事件,颜色样式不起作用) 第一种方法 使用 ...
- 蓝桥杯算法训练<一>
一.图形显示 此题虽然简单,但是需啊哟注意的是,每个“*”后边有一个空格] 问题描述 编写一个程序,首先输入一个整数,例如5,然后在屏幕上显示如下的图形(5表示行数): * * * * * * * * ...
- node.js 中的全局对象
/** * Created by Administrator on 2016/8/29. */ const http = require("http"); const hostna ...
- Object的增。删。查。改。遍历
1.增: 1.向对象添加属性和方法 (私有) ---> obj.属性 =""; 2.向对象原型添加方法 (公共) ---> obj.prototype. ...
- linux创建用户和组
linux下创建用户(一) Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系 ...
- MyEclipse的 lib和Build path(构建路径)(转)
首先两种方式对于放置jar包的方式是不同的: Build path(构建路径):对于种方式来说,可以算是对jar包文件的一个引用.可以引用lib下的jar包,也可以引用本地磁盘上的jar包. WEB- ...