bzoj3998 弦论 后缀自动机

来源:互联网 发布:2016高速公路数据分析 编辑:程序博客网 时间:2024/06/03 21:51

题目大意:

对于给定的一个长度为n的字符串S,求其第k小的子串。询问有两种,一种不重复(本质不同)的子串,另一种要计算重复(位置不同)的子串。

题解:

首先我们可以建一个后缀自动机。
然后每条路径走到每个点都是一个串,它们是有字典序的。
我们只需要统计出往每个点走之后都有多少串(sum[i])就好了。
sum[i]=sum[son[i]]+val[i]
对于不计重复的情况下,val[i]=1
对于计算重复的情况下,val[i]就是该状态的right集合大小。
询问时dfs即可。

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>using namespace std;const int N=500005;int T,n,k;char s[N];struct sam{    int last,cnt;    int son[N<<1][26],fa[N<<1],mx[N<<1],val[N<<1],sum[N<<1];    int v[N],q[N<<1];    sam()    {        last=++cnt;    }    void extend(int c)    {        int p=last,np=last=++cnt;        mx[np]=mx[p]+1;val[np]=1;        while(p&&!son[p][c])son[p][c]=np,p=fa[p];        if(!p)fa[np]=1;        else         {            int q=son[p][c];            if(mx[q]==mx[p]+1)fa[np]=q;            else             {                int nq=++cnt;mx[nq]=mx[p]+1;                memcpy(son[nq],son[q],sizeof(son[q]));                fa[nq]=fa[q];                fa[q]=fa[np]=nq;                while(son[p][c]==q)son[p][c]=nq,p=fa[p];            }        }    }    void pre()    {        for(int i=1;i<=cnt;i++)v[mx[i]]++;        for(int i=1;i<=n;i++)v[i]+=v[i-1];        for(int i=cnt;i>=1;i--)q[v[mx[i]]--]=i;        for(int i=cnt;i>=1;i--)        {            int t=q[i];            if(T==1)val[fa[t]]+=val[t];            else val[t]=1;        }        val[1]=0;        for(int i=cnt;i>=1;i--)        {            int t=q[i];sum[t]=val[t];            for(int j=0;j<26;j++)                sum[t]+=sum[son[t][j]];        }    }    void dfs(int x,int k)    {        if(k<=val[x])return;        k-=val[x];        for(int i=0;i<26;i++)            if(int t=son[x][i])            {                if(k<=sum[t])                {                    putchar(i+'a');                    dfs(t,k);                    return;                }                else k-=sum[t];            }    }}sam;int main(){    //freopen("lx.in","r",stdin);    scanf("%s",s+1);    n=strlen(s+1);    scanf("%d%d",&T,&k);    for(int i=1;i<=n;i++)        sam.extend(s[i]-'a');    sam.pre();    if(k>sam.sum[1])puts("-1");    else sam.dfs(1,k);    return 0;}
原创粉丝点击