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& ...
随机推荐
- Cocos Creator 键盘监听事件
键盘事件键盘.设备重力传感器此类全局事件是通过函数 cc.systemEvent.on(type, callback, target) 注册的.cc.SystemEvent.EventType.KEY ...
- 等比数列二分求和(logn复杂度)
看完这个之后,感觉数学简直太厉害了 转载自:http://blog.csdn.net/acdreamers/article/details/7851144 今天我们学习如何有效地求表达式的值.对于这个 ...
- SpringMVC.入门篇.一.HelloWorld
SpringMVC.入门篇<一>HelloWorld 项目包结构如下: HelloController.java 代码 package com.charles.controller; im ...
- LeetCode110.平衡二叉树
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1. 示例 1: 给定二叉树 [3,9,20,null,null,15,7] 3 / \ 9 20 / \ 15 7 返回 true . 示例 ...
- 软工网络15团队作业4——Alpha阶段敏捷冲刺1.0
软工网络15团队作业4--Alpha阶段敏捷冲刺1.0 1. 各个成员在 Alpha 阶段认领的任务,以及整个项目预期的任务量(使用整数表示,与项目预估的总工作小时数一致.比如项目A预估需120小时才 ...
- strlen实现
1.strlen函数. 普通版实现方法, int strlen( char *s) { int length = 0; while(*s++) length++; return length; } 优 ...
- php核心纪要 整理
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 20155228 实验三 敏捷开发与XP实践
20155228 实验三 敏捷开发与XP实践 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)>& ...
- 20155228 2016-2017-2 《Java程序设计》第10周学习总结
20155228 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 网络 网络是能够波此通信的计算机的集合根据范}到的宽度,网络可以分为局域网和广域网.LAN ...
- ResourceBundle与Properties读取配置文件
ResourceBundle与Properties的区别在于ResourceBundle通常是用于国际化的属性配置文件读取,Properties则是一般的属性配置文件读取. ResourceBundl ...