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& ...
随机推荐
- cocos2d JS 错误异常抛出捕获和崩溃拦截
Error对象 一旦代码解析或运行时发生错误,JavaScript引擎就会自动产生并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方. Error对象的实例有三个最基本的属性: nam ...
- Unity中HideInInspector和SerializeField以及Serializable
首先,Unity会自动为Public变量做序列化,序列化的意思是说再次读取Unity时序列化的变量是有值的,不需要你再次去赋值,因为它已经被保存下来. 然后是,什么样的值会被显示在面板上? 已经被序列 ...
- HttpServletRequest常用方法
1.获取客户机信息 getRequestURL:该方法返回客户端发出请求时的完整URL getRequestURI:该方法返回请求行中的资源名部分 getQueryString:该方法返回请求中的参数 ...
- 安装oracle经验
1.使用database configuration assistant配置和创建数据库 2.使用net manager配置监听 3.使用netconfiguration assistant配置服务
- C++中位运算
简介 1 位逻辑运算符: & (位 “与”) and ----------------- 2个都为1 才是1-----------0^0 = 0 , 0^1 = 0, 1^0 = 0 ...
- d'jang基础
1,建立一个名为guest的django项目,django-admin startproject guest 生成一个guest文件夹,包含一个guest文件夹和一个manage.py cd gue ...
- 多语言(Java、.NET、Node.js)混合架构下开源调用链追踪APM项目初步选型
1. 背景 我们的技术栈包括了Java..NET.Node.js等,并且采用了分布式的技术架构,系统性能管理.问题排查成本越来越高. 2. 基本诉求 针对我们的情况,这里列出了选型的主要条件,作为最终 ...
- C#之Action的实际应用例子
public class DemoAction{ public Action action; public Action<int> action1; public Action<in ...
- Palindrome Bo (预处理 + 区间DP)
先进行离散化,然后再预处理出所有位置的下一个元素,做好这一步对时间的优化非常重要. 剩下的就是一般的DP了.区间DP #include<bits/stdc++.h> using names ...
- Hive批量删除历史分区
批量删除历史分区和数据可以采用如下操作: -- 删除20180101之前的所有分区 alter table example_table_name drop if exists partition (d ...