SPOJ SUBLEX Lexicographical Substring Search - 后缀数组
考虑后缀Trie。依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] - height[i]$。
求出$height$数组后,求一求本质不同的子串个数的前缀和,可以对每个询问二分。
这里可以直接离线,$O(n + m)$扫一扫就好了。
Code
/**
* SPOJ
* Problem#SUBLEX
* Accepted
* Time: 30ms
* Memory: 19456k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; typedef class Pair3 {
public:
int x, y, id;
}Pair3; typedef class Query {
public:
int k, s, t, id; boolean operator < (Query b) const {
return k < b.k;
}
}Query; const int N = 1e5 + , M = ; int n, m;
char str[N], bs[N];
int rk[N << ], sa[N], hei[N], cnt[N];
Pair3 ps[N], buf[N];
Query qs[M]; inline void init() {
scanf("%s", str + );
n = strlen(str + );
scanf("%d", &m);
for (int i = ; i <= m; i++)
scanf("%d", &qs[i].k), qs[i].id = i;
} inline void radix_sort(Pair3* x, Pair3* y) {
int m = ((n > ) ? (n) : ());
memset(cnt, , sizeof(int) * (m + ));
for (int i = ; i <= n; i++) cnt[x[i].y]++;
for (int i = ; i <= m; i++) cnt[i] += cnt[i - ];
for (int i = ; i <= n; i++) y[cnt[x[i].y]--] = x[i];
memset(cnt, , sizeof(int) * (m + ));
for (int i = ; i <= n; i++) cnt[y[i].x]++;
for (int i = ; i <= m; i++) cnt[i] += cnt[i - ];
for (int i = n; i; i--) x[cnt[y[i].x]--] = y[i];
} inline void build_sa() {
for (int i = ; i <= n; i++)
rk[i] = str[i];
for (int k = , dif = ; k <= n; k <<= , dif = ) {
for (int i = ; i <= n; i++)
ps[i].x = rk[i], ps[i].y = rk[i + k], ps[i].id = i;
radix_sort(ps, buf);
rk[ps[].id] = ++dif;
for (int i = ; i <= n; i++)
rk[ps[i].id] = (dif += (ps[i].x != ps[i - ].x || ps[i].y != ps[i - ].y));
if (dif == n)
break;
}
for (int i = ; i <= n; i++)
sa[rk[i]] = i;
} inline void get_height() {
for (int i = , j, k = ; i <= n; i++) {
if (k) k--;
if (rk[i] > ) {
for (j = sa[rk[i] - ]; i + k <= n && j + k <= n && str[i + k] == str[j + k]; k++);
hei[rk[i]] = k;
} else
hei[] = ;
}
} inline void solve() {
build_sa();
get_height();
// for (int i = 1; i <= n; i++)
// cerr << hei[i] << " ";
// cerr << endl;
sort(qs + , qs + m + );
long long cur = ;
for (int i = , nq = , delta; i <= n && nq <= m; i++) {
delta = n - sa[i] + - hei[i];
if (cur + delta < qs[nq].k)
cur += delta;
else {
qs[nq].s = sa[i], qs[nq].t = sa[i] + hei[i] + (qs[nq].k - cur);
nq++, i--;
}
}
for (int i = ; i <= m; i++)
while (qs[i].id != i)
swap(qs[qs[i].id], qs[i]);
for (int i = ; i <= m; i++) {
int len = qs[i].t - qs[i].s;
memcpy(bs, str + qs[i].s , len);
bs[len] = ;
puts(bs);
}
} int main() {
init();
solve();
return ;
}
SPOJ SUBLEX Lexicographical Substring Search - 后缀数组的更多相关文章
- SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组
SUBLEX - Lexicographical Substring Search Little Daniel loves to play with strings! He always finds ...
- spoj 7258 Lexicographical Substring Search (后缀自动机)
spoj 7258 Lexicographical Substring Search (后缀自动机) 题意:给出一个字符串,长度为90000.询问q次,每次回答一个k,求字典序第k小的子串. 解题思路 ...
- spoj SUBLEX (Lexicographical Substring Search) RE的欢迎来看看
SPOJ.com - Problem SUBLEX 这么裸的一个SAM,放在了死破OJ上面就是个坑. 注意用SAM做的时候输出要用一个数组存下来,然后再puts,不然一个一个字符输出会更慢. 还有一个 ...
- Spoj SUBLEX - Lexicographical Substring Search
Dicription Little Daniel loves to play with strings! He always finds different ways to have fun with ...
- SP7258 SUBLEX - Lexicographical Substring Search - 后缀自动机,dp
给定一个字符串,求本质不同排名第k小的子串 Solution 后缀自动机上每条路径对应一个本质不同的子串 按照 TRANS 图的拓扑序,DP 计算出每个点发出多少条路径 (注意区别 TRANS 图的拓 ...
- SPOJ 7258 Lexicographical Substring Search [后缀自动机 DP]
题意:给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个. 第一道自己做的1A的SAM啦啦啦 很简单,建SAM后跑kth就行了 也需要按val基数排序倒着 ...
- SPOJ7258 SUBLEX - Lexicographical Substring Search(后缀自动机)
Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...
- spoj SUBLEX - Lexicographical Substring Search【SAM】
先求出SAM,然后考虑定义,点u是一个right集合,代表了长为dis[son]+1~dis[u]的串,然后根据有向边转移是添加一个字符,所以可以根据这个预处理出si[u],表示串u后加字符能有几个本 ...
- SP7258 SUBLEX - Lexicographical Substring Search(后缀自动机)
传送门 解题思路 首先建\(sam\),然后在拓扑序上\(dp\)一下,把每个点的路径数算出来,然后统计答案时就在自动机上\(dfs\)一下,仿照平衡树那样找第\(k\)小. 代码 #include& ...
随机推荐
- 用log4net记录日志信息
在.net中用log4net记录日志信息,已经是很平常的事情了. log4net下载:http://logging.apache.org/log4net/download_log4net.cgi 百度 ...
- HDU 2254 奥运(矩阵+二分等比求和)
奥运 [题目链接]奥运 [题目类型]矩阵+二分等比求和 &题解: 首先离散化城市,之后就是矩阵快速幂了,但让求的是A^(t1)+A^(t1+1)+...+A^(t2),我先想的是打表,但时间真 ...
- React-Native组件之Text内文字垂直居中方案
style: { height: 100, textAlign: 'center', textAlignVertical: 'center', } 以上方法在Android上显示水平垂直居中, 但在I ...
- JavaScript 深入了解对象中的属性
本篇主要介绍JS中对象的属性,包括:属性的分类.访问方式.检测属性.遍历属性以及属性特性等内容. 目录 1. 介绍:描述属性的命名方式.查找路径以及分类 2. 属性的访问方式:介绍'.'访问方式.'[ ...
- Git SSH密钥对生成以及多个SSH存在情况配置
一.使用Git Bash 生成一个新的SSH密钥 1. 打开 Git Bash. 2. 邮箱设置粘贴下面的文字,替换成为你自己的邮箱. Github SSH 1 $ ssh-keygen -t rsa ...
- Message对象
一)描述 1: 每一个Message对象都包含两个对象: (1)google::protobuf::Descriptor 描述对象,是Message所有Filed的一个集合,它又包含了FieldDes ...
- html5-常用的通用元素
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- CSS小知识-----前缀-moz-、-ms-、-webkit-,-o-分别代表的意思
这种方式在业界上统称:识别码.前缀 -ms-代表[ie]内核识别码 -moz-代表火狐[firefox]内核识别码 -webkit-代表谷歌[chrome]/苹果[safari]内核识别码 -o-代表 ...
- codeforces 984B Minesweeper
题意: 给出一个矩阵,如果一个格子是数字,那么与这个格子相邻的格子中有炸弹的数量必须等于这个格子中的数字: 如果一个格子是空地,那么这个格子的所有相邻的格子中就不能有炸弹. 判断这个矩阵是否合法. 思 ...
- Linux QtCreator 编译报错:No rule to make target '.../***' needed by '***.o'.stop
Linux QtCreator 编译报错:No rule to make target 'mainwindow.cpp' needed by 'mainwindow.o'.stop [1]解决方案 ...