【TJOI2015】—弦论(后缀自动机)

传送门

第一次看见这样强行套两道题的

首先字典序最小的子串肯定是在自动机上贪心

而如果我们第一步走最小的转移

那么第一个字符确定后无论剩下字符是什么,这些子串都绝对是最小的那些

第二小的转移类似

所以我们只需要在SamSam上统计每个点能dfsdfs到的子树大小(虽然这不是一棵树,但其实意思是一样的,毕竟这是一个DAGDAG

其实可以按照lenlen排序后从小往大枚举SamSam上的点点,然后把每个点的所有转移的sizsiz加给它自己

然后就像平衡树查找序列第kk大数一样

枚举字符cc从小到大每一个儿子的转移,如果k>siz[son[k][c]]k>siz[son[k][c]]k=siz[son[k][c]]k-=siz[son[k][c]],走到第一个小等于的转移就走下去,因为要输出走法,所以在每次转移的时候输出转移字符就是了

注意两种情况的不同做法,t=0t=0时是统计ParenttreeParent-tree上的sizesize

把所有非克隆的点赋为11,排序后从大到小把sizsiz加给linklink

t=1t=1时则相当于是统计每个点的endposendpos集合的大小

因为任意的link[x]=link[y]link[x]=link[y]endpos[x]endpos[x]endpos[y]endpos[y]的任意元素都互不相同

所以我们可以保证子树传上来一定就是自己的endposendpos集合大小

t=0t=0时就不需要管出现过几次了,只需要把所有都赋为1就可以了

注意最后会在后缀自动机上跑一次,就是统计所有子串的数量

因为没理解自动机和ParenttreeParent-tree的区别和意义想了好久

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
const int N=500005;
struct node{
    int len,link,nxt[27];
};
#define max(a,b) (((a)>(b))?a:b)
node st[N<<1];
int tot,op,f[N<<1],t[N<<1],g[N<<1],k,siz[N<<1],last,ans;
char a[N];
inline void init(){
    last=tot=1;
}
inline void sa_extend(int c){
    int cur=++tot,p=last;last=cur;
    st[cur].len=st[p].len+1,siz[cur]=1;
    for(;p&&!st[p].nxt[c];p=st[p].link) st[p].nxt[c]=cur;
    if(!p)st[cur].link=1;
    else{
        int q=st[p].nxt[c];
        if(st[p].len+1==st[q].len)st[cur].link=q;
        else {
            int clo=++tot;
            st[clo]=st[q];           
            st[clo].len=st[p].len+1;     
            for(;p&&st[p].nxt[c]==q;p=st[p].link)st[p].nxt[c]=clo;
            st[q].link=st[cur].link=clo;                 
        }
    }
}
int main(){
    scanf("%s",a+1),init();
    int len=strlen(a+1);
    for(int i=1;i<=len;i++)sa_extend(a[i]-'a');
    op=read(),k=read();
    for(int i=1;i<=tot;i++)
        t[st[i].len]++;
    for(int i=1;i<=tot;i++)
        t[i]+=t[i-1];
    for(int i=1;i<=tot;i++)
        g[t[st[i].len]--]=i;
    if(op){
        for(int i=tot;i;i--)
            siz[st[g[i]].link]+=siz[g[i]];
    }
    else{
        for(int i=tot;i;i--)siz[g[i]]=1;
    }
    siz[1]=0;
    for(int i=tot;i;i--){
        f[g[i]]=siz[g[i]];
        for(int j=0;j<26;j++){
            if(st[g[i]].nxt[j])
                f[g[i]]+=f[st[g[i]].nxt[j]];
        }
    }
    if(k>f[1]){
        cout<<-1;return 0;
    }
    int now=1;
    k-=siz[now];
    while(k){
        int p=0;
        while(k>f[st[now].nxt[p]])k-=f[st[now].nxt[p]],++p;
        now=st[now].nxt[p],putchar('a'+p),k-=siz[now];
    }
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366380.html