TJOI2015 弦论

题目描述

题解:

鉴于子串我们很容易想到后缀自动机。

先建后缀自动机,然后处理单点价值以及对于每个点的总价值。

T=0要求去重,此时单点价值为1;

T=0要求不去重,此时单点价值为parent树上endpos的数量。后缀的前缀就是子串。

由于建成的后缀自动机有向无环,我们可以O(n)时间处理每个点的总价值,即sum[u]+=sum[to]。

时间复杂度O(n)。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500050
#define ll long long
char s[N];
int T,K;
struct Point
{
    int pre,len,trs[28];
}p[2*N];
struct SAM
{
    int siz[2*N],v[2*N];
    ll sum[2*N];
    int tot,las;
    SAM(){tot=las=1;}
    int hed[2*N],cnt;
    struct EG
    {
        int to,nxt;
    }e[2*N];
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    void insert(int c)
    {
        int np,nq,lp,lq;
        np=++tot;
        siz[np]=1;
        p[np].len = p[las].len+1;
        for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre)
            p[lp].trs[c]=np;
        if(!lp)p[np].pre = 1;
        else
        {
            lq = p[lp].trs[c];
            if(p[lq].len==p[lp].len+1)p[np].pre = lq;
            else
            {
                nq = ++tot;
                p[nq] = p[lq];
                p[nq].len = p[lp].len+1;
                p[lq].pre = p[np].pre = nq;
                while(p[lp].trs[c]==lq)
                {
                    p[lp].trs[c]=nq;
                    lp=p[lp].pre;
                }
            }
        }
        las = np;
    }
    void dfs1(int u)
    {
        v[u]=T?siz[u]:1;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            dfs1(to);
            if(T)v[u]+=v[to];
        }
    }
    void dfs2(int u)
    {
        sum[u] = v[u];
        for(int i=1;i<=26;i++)
        {
            int to = p[u].trs[i];
            if(!to)continue;
            if(!sum[to])dfs2(to);
            sum[u]+=sum[to];
        }
    }
    void build()
    {
        for(int i=2;i<=tot;i++)
            ae(p[i].pre,i);
        dfs1(1);
        v[1]=0;
        dfs2(1);
    }
    void cal(int k)
    {
        int u = 1;
        if(sum[1]<k)
        {
            printf("-1");
            return ;
        }
        while(1)
        {
            for(int i=1;i<=26;i++)
            {
                if(k>sum[p[u].trs[i]])k-=sum[p[u].trs[i]];
                else
                {
                    printf("%c",'a'+i-1);
                    u = p[u].trs[i];
                    k-= v[u];
                    break;
                }
            }
            if(k<=0)return ;
        }
    }
}sam;
int main()
{
    scanf("%s%d%d",s+1,&T,&K);
    int len = strlen(s+1);
    for(int i=1;i<=len;i++)
        sam.insert(s[i]-'a'+1);
    sam.build();
    sam.cal(K);
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/10098115.html