http://www.spoj.com/problems/SUBLEX/en/
题意简单,思路简单,因为菜鳮所以只能慢慢学。
题意: 给一个串,q次查询,每次输入一个K,输出该串第K小子串。当然所有子串是去重的。
想到子串,我一开始想到的是自动机,虽然后缀数组可做此题,但我个人认为后缀数组处理子串问题较难。
慢慢的,我想既然子串去重了,那么相当于后缀自动机的每一个状态啊,相同的子串在同一个状态里。 建立SAM,之后找字典序第k小的子串,这我们可以用DFS处理出来每个状态下所含有的状态的个数。之后我们按照字典序最小遍历状态即可。
#include <bits/stdc++.h>
#define maxs 2020220
#define mme(i,j) memset(i,j,sizeof(i))
#define ll long long int
using namespace std;
char s[maxs];
int last,tot;
int p,q,np,nq;
int son[maxs][27],pa[maxs],ml[maxs];
int newnode(int x)
{
ml[++tot]=x;
return tot;
}
void add(int id)
{
p=last;
np=newnode(ml[p]+1);
for(;p&&!son[p][id];p=pa[p])
son[p][id]=np;
if(!p)
pa[np]=1;
else {
q=son[p][id];
if(ml[q]==ml[p]+1) pa[np]=q;
else{
nq = newnode(ml[p]+1);
memcpy(son[nq], son[q], sizeof(son[nq]));
pa[nq]=pa[q];
pa[q]=pa[np]=nq;
for(;son[p][id]==q;p=pa[p])
son[p][id]=nq;
}
}
last=np;
}
int cnt[maxs];
int deep(int x)
{
if(cnt[x]!=0) return cnt[x];
cnt[x]=1;
for(int i=0;i<26;i++)
if(son[x][i]) cnt[x]+=deep(son[x][i]);
return cnt[x];
}
void Solve(int now,int k,int len)
{
k--;
if(k==0)
{
s[len]='\0';
printf("%s\n",s+1);
// puts("Not fish");
return ;
}
int to;
for(int i=0;i<26;i++)
{
to=son[now][i];
if(to==0) continue;
if(cnt[to]<k) k-=cnt[to];
else {
s[len]='a'+i;
Solve(to,k,len+1);
// printf("k is %d len is %d\n",k,len);
return ;
}
}
}
int main()
{
int Q,k;
scanf("%s",s);
pa[0]=0;
cnt[0]=0;
son[0][0]=0;
last=tot=1;
// mme(son,0);
for(int i=0;s[i];i++)
add(s[i]-'a');
cnt[1]=deep(1);
scanf("%d",&Q);
while(Q--)
{
scanf("%d",&k);
Solve(1,k+1,1);
// puts("Finish");
}
return 0;
}