[bzoj3998][TJOI2015]弦论——后缀自动机
作者:互联网
题目大意:
给定一个字符串,求它的第k小子串。
思路:
后缀自动机的模板题。
考虑将后缀自动机建出来之后,求出每一个状态在原串中出现了多少次,然后统计以每个节点往后拓展的字符串总共有多少种(按照拓扑序累加即可),最后直接在DAG上做类似二分的就好了。
/*=======================================
* Author : ylsoi
* Time : 2019.2.9
* Problem : bzoj3998
* E-mail : ylsoi@foxmail.com
* ====================================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second #define mk make_pair
#define pb push_back
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj3998.in","r",stdin);
freopen("bzoj3998.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T f=1; char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
_*=f;
}
const int maxn=5e5+10;
int n,ty;
ll m;
char s[maxn];
struct Suffix_Automaton{
struct node{
int len,fa,ch[26];
}t[maxn<<1];
int last,tot;
ll sz[maxn<<1],sum[maxn<<1];
Suffix_Automaton(){last=tot=1;}
void insert(int x){
int p=last,np=last=++tot;
sz[np]=1;
t[np].len=t[p].len+1;
while(p && !t[p].ch[x])t[p].ch[x]=np,p=t[p].fa;
if(!p)t[np].fa=1;
else{
int q=t[p].ch[x];
if(t[q].len==t[p].len+1)t[np].fa=q;
else{
int nq=++tot;
t[nq]=t[q],t[nq].len=t[p].len+1;
t[q].fa=t[np].fa=nq;
while(p && t[p].ch[x]==q)t[p].ch[x]=nq,p=t[p].fa;
}
}
}
int tax[maxn<<1],lis[maxn<<1];
void get_times(){
if(!ty)REP(i,2,tot)sz[i]=1;
else{
REP(i,2,tot)++tax[t[i].len];
REP(i,1,n)tax[i]+=tax[i-1];
REP(i,2,tot)lis[tax[t[i].len]--]=i;
DREP(i,tot-1,1)sz[t[lis[i]].fa]+=sz[lis[i]];
sz[1]=0;
}
}
bool vis[maxn<<1];
void get_num(int o){
if(vis[o])return;
vis[o]=1;
sum[o]=sz[o];
REP(i,0,25){
int v=t[o].ch[i];
if(!v)continue;
get_num(v);
sum[o]+=sum[v];
}
}
void dfs(int o,ll k){
k-=sz[o];
if(k<=0)return;
REP(i,0,25){
int v=t[o].ch[i];
if(!v)continue;
if(k<=sum[v]){
printf("%c",'a'+i);
dfs(v,k);
break;
}
else k-=sum[v];
}
}
}T;
int main(){
// File();
scanf("%s",s+1);
read(ty),read(m);
n=strlen(s+1);
REP(i,1,n)T.insert(s[i]-'a');
T.get_times();
T.get_num(1);
if(T.sum[1]<m)printf("-1");
else T.dfs(1,m);
return 0;
}
标签:ylsoi,后缀,弦论,TJOI2015,isdigit,自动机,bzoj3998,getchar 来源: https://www.cnblogs.com/ylsoi/p/10357631.html