SUBLEX - 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".

Input

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

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

Example

Input:
aaa
2
2
3 Output:
aa
aaa

Edited: Some input file contains garbage at the end. Do not process them.

题意:

  给你一个串

  Q个询问,在其去重子串中,字典序排名为K的字串是哪一个 ,并输出来

题解:

  说一下后缀自动机的做法

  设定F[i] 表示 以状态i为起点 所能 形成的不同字串的个数

  求出来,再类似于贪心的找法求出答案串

  后缀数组做更简单些

后缀自动机

#include <bits/stdc++.h>
inline long long read(){long long x=,f=;char ch=getchar();while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}return x*f;}
using namespace std; const int N = 3e5+; const long long mod = ; int isPlus[N * ],endpos[N * ];int d[N * ];
int tot,slink[*N],trans[*N][],minlen[*N],maxlen[*N],pre;
int newstate(int _maxlen,int _minlen,int* _trans,int _slink){
maxlen[++tot]=_maxlen;minlen[tot]=_minlen;
slink[tot]=_slink;
if(_trans)for(int i=;i<;i++)trans[tot][i]=_trans[i],d[_trans[i]]+=;
return tot;
}
int add_char(char ch,int u){
int c=ch-'a',v=u;
int z=newstate(maxlen[u]+,-,NULL,);
isPlus[z] = ;
while(v&&!trans[v][c]){trans[v][c]=z;d[z]+=;v=slink[v];}
if(!v){ minlen[z]=;slink[z]=;return z;}
int x=trans[v][c];
if(maxlen[v]+==maxlen[x]){slink[z]=x;minlen[z]=maxlen[x]+;return z;}
int y=newstate(maxlen[v]+,-,trans[x],slink[x]);
slink[z]=slink[x]=y;minlen[x]=minlen[z]=maxlen[y]+;
while(v&&trans[v][c]==x){trans[v][c]=y;d[x]--,d[y]++;v=slink[v];}
minlen[y]=maxlen[slink[y]]+;
return z;
}
void init_sam() {
for(int i = ; i <= tot; ++i)
for(int j = ; j < ; ++j) trans[i][j] = ;
pre = tot = ;
}
long long f[N],all[N];
char a[N];
int cnt[N],pos[N];
void query(long long k) {
int p = ;
while(k) {
long long now = ;
for(int i = ; i < ; ++i) {
if(!trans[p][i]) continue;
if(f[trans[p][i]] >= k) {
k--;
p = trans[p][i];
printf("%c",i+'a');
break;
}
else k -= f[trans[p][i]];
}
}
printf("\n");
}
int main() {
scanf("%s",a);
int n = strlen(a);
init_sam();
for(int i = ; i < n; ++i)
pre = add_char(a[i],pre);
for(int i = ; i <= n; ++i) cnt[i] = ;
for(int i = ; i <= tot; ++i) cnt[maxlen[i]]++,all[i] = maxlen[i] - minlen[i] + ;
for(int i = ; i <= n; ++i) cnt[i] += cnt[i-];
for(int i = tot; i >= ; --i) pos[cnt[maxlen[i]]--] = i; //for(int i = 2; i <= tot; ++i) cout<<all[i]<<" "<<slink[i]<<endl; for(int i = tot; i >= ; --i) {
int v = pos[i];
f[v] = ;
for(int j = ; j < ; ++j) {
f[v] += f[trans[v][j]];
}
}
int Q;
scanf("%d",&Q);
while(Q--) {
long long k;
scanf("%lld",&k);
query(k);
}
return ;
}

后缀数组

#include <bits/stdc++.h>
inline long long read(){long long x=,f=;char ch=getchar();while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}return x*f;}
using namespace std; const int N = 3e5+; const long long mod = ; int *ran,r[N],sa[N],height[N],wa[N],wb[N],wm[N];
bool cmp(int *r,int a,int b,int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
void SA(int *r,int *sa,int n,int m) {
int *x=wa,*y=wb,*t;
for(int i=;i<m;++i)wm[i]=;
for(int i=;i<n;++i)wm[x[i]=r[i]]++;
for(int i=;i<m;++i)wm[i]+=wm[i-];
for(int i=n-;i>=;--i)sa[--wm[x[i]]]=i;
for(int i=,j=,p=;p<n;j=j*,m=p){
for(p=,i=n-j;i<n;++i)y[p++]=i;
for(i=;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=;i<m;++i)wm[i]=;
for(i=;i<n;++i)wm[x[y[i]]]++;
for(i=;i<m;++i)wm[i]+=wm[i-];
for(i=n-;i>=;--i)sa[--wm[x[y[i]]]]=y[i];
for(t=x,x=y,y=t,i=p=,x[sa[]]=;i<n;++i) {
x[sa[i]]=cmp(y,sa[i],sa[i-],j)?p-:p++;
}
}
ran=x;
}
void Height(int *r,int *sa,int n) {
for(int i=,j=,k=;i<n;height[ran[i++]]=k)
for(k?--k:,j=sa[ran[i]-];r[i+k] == r[j+k];++k);
} int n;
long long f[N];
char a[N];
void query(long long k) {
int pos = lower_bound(f+,f+n+,k) - f;
long long lll = k - f[pos-] + height[pos];
for(int i = sa[pos]; i < sa[pos]+lll; ++i)
printf("%c",a[i]);
printf("\n");
}
int main() {
scanf("%s",a);
n = strlen(a);
for(int i = ; i < n; ++i) r[i] = a[i] - 'a'+;
r[n] = ;
SA(r,sa,n+,);
Height(r,sa,n);
for(int i = ; i <= n; ++i)
f[i] = f[i-] + n - sa[i] - height[i]; int Q;
long long k;
scanf("%d",&Q);
while(Q--) {
scanf("%lld",&k);
query(k);
}
return ;
}

SPOJ SUBLEX - Lexicographical Substring Search 后缀自动机 / 后缀数组的更多相关文章

  1. Spoj SUBLEX - Lexicographical Substring Search

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

  2. SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

    题目传送门 传送门I 传送门II 题目大意 给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它. 考虑后缀Trie.依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] ...

  3. spoj SUBLEX (Lexicographical Substring Search) RE的欢迎来看看

    SPOJ.com - Problem SUBLEX 这么裸的一个SAM,放在了死破OJ上面就是个坑. 注意用SAM做的时候输出要用一个数组存下来,然后再puts,不然一个一个字符输出会更慢. 还有一个 ...

  4. spoj SUBLEX - Lexicographical Substring Search【SAM】

    先求出SAM,然后考虑定义,点u是一个right集合,代表了长为dis[son]+1~dis[u]的串,然后根据有向边转移是添加一个字符,所以可以根据这个预处理出si[u],表示串u后加字符能有几个本 ...

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

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

  6. Lexicographical Substring Search (spoj7259) (sam(后缀自动机)+第k小子串)

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

  7. ●SPOJ 7258 Lexicographical Substring Search

    题链: http://www.spoj.com/problems/SUBLEX/题解: 后缀自动机. 首先,因为相同的子串都被存在了自动机的同一个状态里面,所以这就很自然的避免了重复子串的问题. 然后 ...

  8. SPOJ 7258 Lexicographical Substring Search(后缀自动机)

    [题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...

  9. SP7258 SUBLEX - Lexicographical Substring Search - 后缀自动机,dp

    给定一个字符串,求本质不同排名第k小的子串 Solution 后缀自动机上每条路径对应一个本质不同的子串 按照 TRANS 图的拓扑序,DP 计算出每个点发出多少条路径 (注意区别 TRANS 图的拓 ...

随机推荐

  1. AC日记——中庸之道 codevs 2021

    2021 中庸之道  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 给定一个长度为N的序列 ...

  2. BZOJ1858 [Scoi2010]序列操作(线段树)

    题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...

  3. Android 日期对话框DatePickerDialog

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@ ...

  4. htop简介

    htop可谓top的升级版,top不可以鼠标操作,但是htop可以使用鼠标操作 启动方式:命令行下输入htop直接启动,启动后的界面如图所示 操作:可以使用上下左右方向键进行移动查看.可以使用鼠标点击 ...

  5. NV 3D投影方案 【转】

    http://tu.pcpop.com/all-677013.htm 1/8 NVIDIA 3D方案涉及图形处理器(GPU).信号发射器.快门式3D眼镜.3D播放软件以及经过NVIDIA认证的显示器. ...

  6. VS2010 C#调用C++ DLL文件 【转】

    http://www.soaspx.com/dotnet/csharp/csharp_20110406_7469.html 背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第 ...

  7. 转:Java 自动装箱与拆箱(Autoboxing and unboxing)

    转: http://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html 什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing) ...

  8. DevExpress控件之TreeList

    基于v18.1 使用AppendNode方法手动赋值时,首先要添加treeListColumn 默认样式                                     修改后的样式   1 ...

  9. java集合类型接口和实现类个人总结

    转载:http://blog.csdn.net/qingchunbusanchang/article/details/39576749 java的集合是一个比较综合的概念,相关的知识有很多的博客里面做 ...

  10. x86 Android游戏开发专题篇之使用google breakpad捕捉c++崩溃(以cocos2dx为例)

    近期一直都在x86设备上进行游戏开发.就c++层和Android java层倒没有什么要特别注意的(除了须要注意一下改动Application.mk指定平台外),在c++崩溃的时候,非常多时候看不到堆 ...