3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2024 Solved: 665
[ Submit][ Status][ Discuss]
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3
0 3
Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9
Source
题解:后缀自动机
这道题T=0的时候就是SPOJ7258.
T=1的时候因为位置不同的子串也算不同,所以我们需要知道每个状态的|right|.进行计算的时候初值不是1,而是当前点的|right|
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000003
using namespace std;
int n,m,cnt,last,p,q,nq,np,root,T;
int ch[N][30],fa[N],l[N],size[N],pos[N],v[N],r[N];
char s[N];
void extend(int x)
{
int c=s[x]-'a';
p=last; np=++cnt; last=np;
l[np]=x;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if (!p) fa[np]=root;
else {
q=ch[p][c];
if (l[q]==l[p]+1) fa[np]=q;
else {
nq=++cnt; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[nq]);
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void solve()
{
for (int i=cnt;i>=1;i--){
int t=pos[i];
if (t!=1) size[t]++;
for (int j=0;j<26;j++)
if (ch[t][j]) size[t]+=size[ch[t][j]];
}
}
void solve1()
{
p=1;
for (int i=1;i<=n;i++) {
p=ch[p][s[i]-'a'];
r[p]++;
}
for (int i=cnt;i>=1;i--){
int t=pos[i];
r[fa[t]]+=r[t];
}
for (int i=cnt;i>=1;i--){
int t=pos[i];
if (t!=1) size[t]+=r[t];
for (int j=0;j<26;j++)
if (ch[t][j]) size[t]+=size[ch[t][j]];
}
}
void pri(int x)
{
p=1;
while (x){
for (int i=0;i<26;i++)
if (ch[p][i])
if (x>size[ch[p][i]]) x-=size[ch[p][i]];
else {
putchar(i+97);
if (T==0) x--;
else x-=r[ch[p][i]];
p=ch[p][i];
break;
}
if (x<0) break;
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1); last=root=++cnt;
for (int i=1;i<=n;i++) extend(i);
scanf("%d%d",&T,&m);
for (int i=1;i<=cnt;i++) v[l[i]]++;
for (int i=1;i<=n;i++) v[i]+=v[i-1];
for (int i=1;i<=cnt;i++) pos[v[l[i]]--]=i;
if (T==0) solve();
else solve1();
//for (int i=1;i<=cnt;i++) cout<<r[i]<<" ";
//cout<<endl;
//for (int i=1;i<=cnt;i++) cout<<l[i]<<" ";
//cout<<endl;
if (m>size[1]) {
printf("-1\n");
return 0;
}
pri(m); printf("\n");
}