[SPOJ7258]Lexicographical Substring Search

试题描述

Little Daniel loves to play with strings! He always finds different ways to have fun with strings! Knowing that, his friend Kinan decided to test his skills so he gave him a string S and asked him Q questions of the form:

If all distinct substrings of string S were sorted lexicographically, which one will be the K-th smallest?

After knowing the huge number of questions Kinan will ask, Daniel figured out that he can't do this alone. Daniel, of course, knows your exceptional programming skills, so he asked you to write him a program which given S will answer Kinan's questions.

Example:

S = "aaa" (without quotes)
substrings of S are "a" , "a" , "a" , "aa" , "aa" , "aaa". The sorted list of substrings will be:
"a", "aa", "aaa".

输入

In the first line there is Kinan's string S (with length no more than 90000 characters). It contains only small letters of English alphabet. The second line contains a single integer Q (Q <= 500) , the number of questions Daniel will be asked. In the next Q lines a single integer K is given (0 < K < 2^31).

输出

Output consists of Q lines, the i-th contains a string which is the answer to the i-th asked question.

输入示例

aaa

输出示例

aa
aaa

题解

这题其实就是这道题的一个子问题。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 90010 char S[maxn];
int n, rank[maxn], height[maxn], sa[maxn], Ws[maxn]; bool cmp(int* a, int p1, int p2, int l) {
if(p1 + l > n && p2 + l > n) return a[p1] == a[p2];
if(p1 + l > n || p2 + l > n) return 0;
return a[p1] == a[p2] && a[p1+l] == a[p2+l];
}
void ssort() {
int *x = rank, *y = height;
int m = 0;
for(int i = 1; i <= n; i++) Ws[x[i] = S[i]]++, m = max(m, x[i]);
for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1];
for(int i = n; i; i--) sa[Ws[x[i]]--] = i;
for(int j = 1, pos = 0; pos < n; j <<= 1, m = pos) {
pos = 0;
for(int i = n - j + 1; i <= n; i++) y[++pos] = i;
for(int i = 1; i <= n; i++) if(sa[i] > j) y[++pos] = sa[i] - j;
for(int i = 1; i <= m; i++) Ws[i] = 0;
for(int i = 1; i <= n; i++) Ws[x[i]]++;
for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1];
for(int i = n; i; i--) sa[Ws[x[y[i]]]--] = y[i];
swap(x, y); pos = 1; x[sa[1]] = 1;
for(int i = 2; i <= n; i++) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? pos : ++pos;
}
return ;
}
void calch() {
for(int i = 1; i <= n; i++) rank[sa[i]] = i;
for(int i = 1, j, k = 0; i <= n; height[rank[i++]] = k)
for(k ? k-- : 0, j = sa[rank[i]-1]; S[j+k] == S[i+k]; k++);
return ;
} int en[maxn]; int main() {
scanf("%s", S + 1);
n = strlen(S + 1); ssort();
calch();
for(int i = 1; i <= n; i++) en[i] = n - sa[i] + 1 - height[i];
for(int i = 1; i <= n; i++) en[i] += en[i-1];
int q = read();
while(q--) {
int k = read(), p = lower_bound(en + 1, en + n + 1, k) - en;
int l = sa[p], r = n - (en[p] - k);
for(int i = l; i <= r; i++) putchar(S[i]); putchar('\n');
} return 0;
}

这道题用后缀自动机也是可以滴。对于每个节点 i 我们维护一发 f(i) 表示状态 i 之后总共有多少种填法,然后我们每一位枚举填哪个字母,看后续状态数是否 ≥ k。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 180010
#define maxa 26 char S[maxn];
int n; int rt, last, ToT, ch[maxn][maxa], par[maxn], Max[maxn], f[maxn];
void extend(int x) {
int p = last, np = ++ToT; Max[np] = Max[p] + 1; f[np] = 1; last = np;
while(p && !ch[p][x]) ch[p][x] = np, p = par[p];
if(!p){ par[np] = rt; return ; }
int q = ch[p][x];
if(Max[q] == Max[p] + 1){ par[np] = q; return ; }
int nq = ++ToT; Max[nq] = Max[p] + 1; f[nq] = 1;
memcpy(ch[nq], ch[q], sizeof(ch[q]));
par[nq] = par[q];
par[q] = par[np] = nq;
while(p && ch[p][x] == q) ch[p][x] = nq, p = par[p];
return ;
}
int sa[maxn], Ws[maxn];
void build() {
for(int i = 1; i <= ToT; i++) Ws[n-Max[i]]++;
for(int i = 1; i <= n; i++) Ws[i] += Ws[i-1];
for(int i = ToT; i; i--) sa[Ws[n-Max[i]]--] = i;
for(int i = 1; i <= ToT; i++)
for(int c = 0; c < maxa; c++) f[sa[i]] += f[ch[sa[i]][c]];
return ;
} int main() {
scanf("%s", S); n = strlen(S);
rt = last = ToT = 1;
for(int i = 0; i < n; i++) extend(S[i] - 'a');
build();
// for(int i = 1; i <= ToT; i++) printf("%d%c", f[i], i < ToT ? ' ' : '\n'); int q = read();
while(q--) {
int k = read(), p = rt;
while(k)
for(int c = 0; c < maxa; c++) if(ch[p][c])
if(f[ch[p][c]] >= k) {
putchar(c + 'a'); k--; p = ch[p][c]; break;
}
else k -= f[ch[p][c]];
putchar('\n');
} return 0;
}

[SPOJ7258]Lexicographical Substring Search的更多相关文章

  1. 2018.12.22 spoj7258 Lexicographical Substring Search(后缀自动机)

    传送门 samsamsam基础题. 题意简述:给出一个串,询问第kkk大的本质不同的串. 然而这就是弦论的简化版. 我们把samsamsam建出来然后贪心选择就行了. 代码: #include< ...

  2. spoj 7258 Lexicographical Substring Search (后缀自动机)

    spoj 7258 Lexicographical Substring Search (后缀自动机) 题意:给出一个字符串,长度为90000.询问q次,每次回答一个k,求字典序第k小的子串. 解题思路 ...

  3. SPOJ SUBLEX 7258. Lexicographical Substring Search

    看起来像是普通的SAM+dfs...但SPOJ太慢了......倒腾了一个晚上不是WA 就是RE ..... 最后换SA写了...... Lexicographical Substring Searc ...

  4. SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组

    SUBLEX - Lexicographical Substring Search Little Daniel loves to play with strings! He always finds ...

  5. Lexicographical Substring Search SPOJ - SUBLEX (后缀数组)

    Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串 ...

  6. Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

    Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串 ...

  7. SPOJ7258 SUBLEX - Lexicographical Substring Search(后缀自动机)

    Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...

  8. SPOJ7258 SUBLEX - Lexicographical Substring Search

    传送门[洛谷] 心态崩了我有妹子 靠 我写的记忆化搜索 莫名WA了 然后心态崩了 当我正要改成bfs排序的时候 我灵光一动 md我写的i=0;i<25;i++??? 然后 改过来就A掉了T^T ...

  9. 【SPOJ 7258】Lexicographical Substring Search

    http://www.spoj.com/problems/SUBLEX/ 好难啊. 建出后缀自动机,然后在后缀自动机的每个状态上记录通过这个状态能走到的不同子串的数量.该状态能走到的所有状态的f值的和 ...

随机推荐

  1. ZooKeeper通过ACL修复未授权访问漏洞

    默认情况下ZooKeeper允许匿名访问,因此在安全漏洞扫描中暴漏未授权访问漏洞. 一.参考资料 <ZooKeeper 笔记(5) ACL(Access Control List)访问控制列表& ...

  2. TRUNCATE TABLE 与 DELETE (转)

    TRUNCATE TABLE 删除表中的所有行,而不记录单个行删除操作.TRUNCATE TABLE 与没有 WHERE 子句的 DELETE 语句类似:但是,TRUNCATE TABLE 速度更快, ...

  3. commons-lang常用工具类StringEscapeUtils使用--转

    https://my.oschina.net/ydsakyclguozi/blog/341496 在apache commons-lang(2.3以上版本)中为我们提供了一个方便做转义的工具类,主要是 ...

  4. 阿里云服务器 Access to the path '....' is denied.解决方法

    昨天公司项目迁移服务器,从自己服务器迁移到阿里云服务器,部署完成后发现有一个页面要读取磁盘上的静态文件就报错了... 如图: 解决办法: 在 Web.Config 的 <System.Web&g ...

  5. jquery基础知识点总结

    Jquery是一个优秀的js库,它简化了js的复杂操作,不需要关心浏览器的兼容问题,提供了大量实用方法. Jquery的写法 方法函数化 链式操作 取值赋值合体] $(“p”).html();   取 ...

  6. H.264学习笔记1——相关概念

    此处记录学习AVC过程中的一些基本概念,不定时更新. frame:帧,相当于一幅图像,包含一个亮度矩阵和两个色度矩阵. field:场,一帧图像,通过隔行扫描得到奇偶两场,分别称为顶场和底场或奇场和偶 ...

  7. 到T-SQL DML 三级的阶梯:在SQL server中实现关系模型

    作者: Gregory Larsen, 2017/08/02 (第一次出版: 2011/11/09) 翻译:谢雪妮,许雅莉,赖慧芳,刘琼滨 译文: 系列 该文章是阶梯系列的一部分:T-SQL DML的 ...

  8. PostgreSQL 数据库错误状态编号解释[附带列表

    PostgreSQL 服务器发出的所有消息都赋予了五个字符的错误代码, 这些代码遵循 SQL 的 "SQLSTATE" 代码的习惯.需要知道发生了什么错误条件的应用通常应该测试错误 ...

  9. CRegKey

    1.简介 CRegKey提供了对系统注册表的操作方法,通过CRegKey类,可以方便的打开注册表的某个分支或子键(CRegKey::Open),可以方便的修改一个键的键值(CRegKey::SetVa ...

  10. MFCEditBox如何自动换行

    设置该EditBox属性: 1.Auto HScroll             False 2.OEM Convert           False 3.Want Return           ...