spoj7258. Lexicographical Substring Search
求一个串的所有不同子串中字典序第k大的。
利用后缀自动机,拓扑排序后通过子边dp,可以计算当前状态可接受的后缀还有多少个串。
然后不断转移即可。
由于卡常数,需要两个优化:
1.预处理将空儿子去掉,减少转移复杂度。
2.优化输出,将要输出的串保存在一个char数组中,最后一起输出。会比一个字符一个字符快些。
最后吐槽一句,SPOJ这破评测机……
求一个串的所有不同子串中字典序第k大的。
利用后缀自动机,拓扑排序后通过子边dp,可以计算当前状态可接受的后缀还有多少个串。
然后不断转移即可。
由于卡常数,需要两个优化:
1.预处理将空儿子去掉,减少转移复杂度。
2.优化输出,将要输出的串保存在一个char数组中,最后一起输出。会比一个字符一个字符快些。
最后吐槽一句,SPOJ这破评测机……
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Maxn 90009
int root,last;//sam
int tots;
int fi[Maxn*2],ne[510000],to[510000],al[510000];
int te;
int tot[Maxn*2];
char str[Maxn];
struct sam_node{
int fa,son[26];
int len;
void init(int _len){len=_len;fa=-1;memset(son,-1,sizeof(son));}
}t[Maxn*2];//length*2
void sam_init(){
tots=0;
root=last=0;
t[tots].init(0);
}
void extend(int w){
//int w=ch-'a';
int p=last;
int np=++tots;t[tots].init(t[p].len+1);
int q,nq;
while(p!=-1&&t[p].son[w]==-1){t[p].son[w]=np;p=t[p].fa;}
if (p==-1) t[np].fa=root;
else{
q=t[p].son[w];
if (t[p].len+1==t[q].len){t[np].fa=q;}
else{
nq=++tots;t[nq].init(0);
t[nq]=t[q];
t[nq].len=t[p].len+1;
t[q].fa=nq;t[np].fa=nq;
while(p!=-1&&t[p].son[w]==q){t[p].son[w]=nq;p=t[p].fa;}
}
}
last=np;
}
int w[Maxn],r[Maxn*2],l;
void topsort(){
int i;
for(i=0;i<=l;++i) w[i]=0;
for(i=1;i<=tots;++i)w[t[i].len]++;
for(i=1;i<=l;++i) w[i]+=w[i-1];
for(i=tots;i>=1;--i)r[w[t[i].len]--]=i;
}
void work(int k){
int i;
int p=root,tmp;
int e,tl;
tl=0;
while(--k){
for(e=fi[p];~e;e=ne[e]){
tmp=tot[to[e]];
if (tmp>=k) {p=to[e];str[tl++]=al[e]+'a';break;}
else {k-=tmp;}
}
}
str[tl]='\0';
puts(str);
}
inline void addedge(int u,int v,int j){
te++;
ne[te]=fi[u];fi[u]=te;to[te]=v;al[te]=j;
}
char s[Maxn];
int i,u,ttot,j,q,k;
int main(){
scanf("%s",s);
sam_init();
l=strlen(s);
for(i=0;i<l;++i){
extend(s[i]-'a');
}
topsort();
for(i=0;i<=tots;++i) fi[tots]=-1;
te=0;
r[0]=0;
for(i=tots;i>=0;--i){
u=r[i];
ttot=1;
for(j=25;j>=0;--j){
if (~t[u].son[j]) {
ttot+=tot[t[u].son[j]];
addedge(u,t[u].son[j],j);
}
}
tot[u]=ttot;
}
scanf("%d",&q);
for(i=1;i<=q;++i){
scanf("%d",&k);
work(k+1);
}
return 0;
}