[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. java IO流 复制图片

    (一)使用字节流复制图片 //字节流方法 public static void copyFile()throws IOException { //1.获取目标路径 //(1)可以通过字符串 // St ...

  2. jquery基础知识点总结

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

  3. 微信小程序组件解读和分析:十三、radio单选项目

    radio单选项目组件说明: radio:单选项目. radio-group: 单项选择器,内部由多个<radio/>组成. radio单选项目示例代码运行效果如下: 下面是WXML代码: ...

  4. [翻译] API测试最佳实践 - 组织你的测试

    组织你的测试 适用级别:初学者 在最底层,一个测试步骤(Test Step)用来验证一个单独的操作.组合若干测试步骤到测试用例,允许你验证那些被分隔出来的一个一个的功能,这些功能是应用程序所需要的.接 ...

  5. 添加QScintilla时显示无法解析的外部函数

    转载请注明出处:http://www.cnblogs.com/dachen408/p/7147165.html 问题:添加QScintilla时显示无法解析的外部函数 解决方案:去掉头文件qscisc ...

  6. Sass的的使用一

    sass -v 检测是否安装 Sass 成功 gem update sass 更新 Sass gem uninstall sass 删除/卸载 Sass 的编译有多种方法: 1.命令编译2.GUI工具 ...

  7. linux下PPTP Server测试环境搭建

    1.1  服务器软件安装 安裝PPTP  Server 所需的软件: 安装PPTP: sudo apt-get install pptpd PPTP Server的软件安装很简单,只需要安装pptpd ...

  8. Kotlin:数组、字符串模板

    一.数组 Kotlin 中的数组是带有类型参数的类,其元素类型被指定为相应的类型参数,使用 Array 类来表示, Array 类定义了 get 与 set 函数(按照运算符重载约定这会转变为 [ ] ...

  9. struts2 使用json

    前台代码: Struts.xml: UserAction: 注意: 1)struts类库里面没有提供ezmorph-1.0.6.jar文件,所以要手动添加:

  10. sql中递归查询

    with AA as ( select * from tb_ClientBranch_Category where BRANCH_MOM_NAME='北京易华录信息技术股份有限公司' union al ...