[TJOI2015]弦论
题目描述
为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?
输入输出格式
输入格式:
第一行是一个仅由小写英文字母构成的字符串s
第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。
输出格式:
输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。
输入输出样例
说明
数据范围
对于10%的数据,n ≤ 1000。
对于50%的数据,t = 0。
对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。
建出后缀自动机之后,记录一下每个节点有多少个可以到达的字串。。
t=0的时候每个节点的权值是1,否则就是它的right集合的大小。。
然后一遍dfs预处理之后再扫一遍就可以得到答案了。。。
#include<bits/stdc++.h> #define ll long long #define maxn 2000050 using namespace std; int a[maxn],c[maxn],pre=1; int f[maxn],ch[maxn][26],cnt=1; int l[maxn],siz[maxn],n,k,t; ll tot[maxn]; char s[maxn]; inline void ins(int x){ int p=pre,np=++cnt; pre=np,l[np]=l[p]+1; siz[np]=1; for(;p&&!ch[p][x];p=f[p]) ch[p][x]=np; if(!p) f[np]=1; else{ int q=ch[p][x]; if(l[q]==l[p]+1) f[np]=q; else{ int nq=++cnt; l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); f[nq]=f[q]; f[q]=f[np]=nq; for(;ch[p][x]==q;p=f[p]) ch[p][x]=nq; } } } inline void build(){ for(int i=0;i<n;i++) ins(s[i]-'a'); if(t){ for(int i=1;i<=cnt;i++) c[l[i]]++; for(int i=n;i>=0;i--) c[i]+=c[i+1]; for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i; for(int i=1;i<=cnt;i++){ int now=a[i]; siz[f[now]]+=siz[now]; } } else{ fill(siz+1,siz+cnt+1,1); } } void dfs1(int x){ tot[x]=siz[x]; for(int i=0;i<26;i++) if(ch[x][i]){ if(!tot[ch[x][i]]) dfs1(ch[x][i]); tot[x]+=tot[ch[x][i]]; } } void dfs2(int x){ if(k<=siz[x]){ k=0,puts(""); return; } k-=siz[x]; for(int i=0;i<26;i++) if(ch[x][i]){ if(k>tot[ch[x][i]]) k-=tot[ch[x][i]]; else putchar('a'+i),dfs2(ch[x][i]); if(!k) return; } } inline void solve(){ siz[1]=0; dfs1(1); if(k>tot[1]) puts("-1"); else dfs2(1); } int main(){ scanf("%s",s),n=strlen(s); scanf("%d%d",&t,&k); build(); solve(); return 0; }
我爱学习,学习使我快乐