【bzoj3998】 TJOI2015—弦论

时间:2023-03-09 18:14:54
【bzoj3998】 TJOI2015—弦论

http://www.lydsy.com/JudgeOnline/problem.php?id=3998 (题目链接)

题意

  给出一个字符串,求它的字典序第K小的子串是什么,分情况讨论不在同一位置的相同子串需不需要重复考虑。

Solution

  对于不需要重复考虑的情况,直接就是spoj上的那道例题,而需要重复考虑的情况不过就是预处理sum的时候每次加上的是当前节点的right集合大小。

代码

// bzoj3998
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=500010;
int n,T,K;
char s[maxn],ans[maxn]; namespace SAM {
int last,Dargen,sz,n;
int len[maxn<<1],ch[maxn<<1][26],par[maxn<<1];
int b[maxn],id[maxn<<1],sum[maxn<<1],r[maxn<<1];
void Extend(int c) {
int np=++sz,p=last;last=np;
len[np]=len[p]+1;
for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
if (!p) par[np]=Dargen;
else {
int q=ch[p][c];
if (len[q]==len[p]+1) par[np]=q;
else {
int nq=++sz;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
par[nq]=par[q];
par[np]=par[q]=nq;
for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
}
}
}
void build() {
last=Dargen=sz=1;
n=strlen(s+1);
for (int i=1;i<=n;i++) Extend(s[i]-'a');
}
void pre() {
for (int i=1;i<=sz;i++) b[len[i]]++;
for (int i=1;i<=n;i++) b[i]+=b[i-1];
for (int i=1;i<=sz;i++) id[b[len[i]]--]=i;
if (!T) {
for (int i=1;i<=sz;i++) r[i]=1;
for (int S=0,i=sz;i>=1;i--,S=0) {
for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
sum[id[i]]=S+1;
}
}
else {
for (int p=Dargen,i=1;i<=n;i++) p=ch[p][s[i]-'a'],r[p]++;
for (int i=sz;i>=1;i--) r[par[id[i]]]+=r[id[i]];
for (int S=0,i=sz;i>=1;i--,S=0) {
for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
sum[id[i]]=S+r[id[i]];
}
}
}
void query() {
int tot=0,p=Dargen;
while (K>0) {
for (int i=0;i<26;i++) if (ch[p][i]) {
if (sum[ch[p][i]]>=K) {
p=ch[p][i];K-=r[p];
ans[++tot]=i+'a';
break;
}
else K-=sum[ch[p][i]];
}
}
ans[++tot]='\0';
}
}
using namespace SAM; int main() {
scanf("%s",s+1);
scanf("%d%d",&T,&K);
build();
pre();
query();
puts(ans+1);
return 0;
}