SPOJ SUBLEX Lexicographical Substring Search

来源:互联网 发布:爱淘宝 编辑:程序博客网 时间:2024/05/19 05:34

SPOJ SUBLEX Lexicographical Substring Search

SAM,后缀自动机,计数

题意

给一个字符串S,将他的所有子串(去重)按字典序排序,给q个询问,问拍第k个子串是谁。

思路

后缀自动机的计数问题。后缀自动机每个状态都代表一个或几个字符串。统计每个节点能到达多少个跟他具有相同前缀的字符串。

换句话说就是统计每个点通过trans边能到多少个串。方法可以dfs,也可以基排。基排就是处理出拓扑序后从后往前更新。

处理好subamo数组后,查找时尽量走小的边。就获得了最终rank(k)的字符串。

代码

#include <bits/stdc++.h>#define M(a,b) memset(a,b,sizeof(a))typedef long long LL;using namespace std;const int MAXL=100005;const int MAXS=26;struct SAM{    int n, len, st;    int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], subamo[2*MAXL+10];    int new_state(int _maxlen, int _minlen, int* _trans, int _slink)    {        n++;        maxlen[n]=_maxlen;        minlen[n]=_minlen;        subamo[n]=1;        for(int i=0; i<MAXS; i++)        {            if(_trans==NULL)                trans[n][i]=0;            else                trans[n][i]=_trans[i];        }        slink[n]=_slink;        return n;    }    int add_char(char ch, int u)    {        int c=ch-'a';        int z=new_state(maxlen[u]+1, -1, NULL, 0);        int v=u;        while(v!=0&&trans[v][c]==0)        {            trans[v][c]=z;            v=slink[v];        }        if(v==0)        {            minlen[z]=1;            slink[z]=1;            return z;        }        int x=trans[v][c];        if(maxlen[v]+1==maxlen[x])        {            minlen[z]=maxlen[x]+1;            slink[z]=x;            return z;        }        int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]);        minlen[x]=maxlen[y]+1;        slink[x]=y;        minlen[z]=maxlen[y]+1;        slink[z]=y;        int w=v;        while(w!=0&&trans[w][c]==x)        {            trans[w][c]=y;            w=slink[w];        }        minlen[y]=maxlen[slink[y]]+1;        return z;    }    void init()    {        memset(maxlen, 0, sizeof(maxlen));        memset(minlen, 0, sizeof(maxlen));        memset(trans, 0, sizeof(maxlen));        memset(slink, 0, sizeof(maxlen));        n=0;        st=new_state(0, -1, NULL, 0);    }    void addstring(char* s, int len)    {        int la=st;        for(int i=0;i<len;i++)        {            la=add_char(s[i], la);        }        this->len=len;    }    int ji[MAXL+10], id[2*MAXL+10];    void prepare()    {        memset(ji, 0, sizeof(ji)), memset(id, 0, sizeof(id));        ji[0]=0;        for(int i=st;i<=n;i++) ji[maxlen[i]]++;        for(int i=1;i<=n;i++) ji[i]+=ji[i-1];        for(int i=st;i<=n;i++) id[ji[maxlen[i]]--]=i;        for(int i=n;i>=st;i--)        {            int now=id[i];            for(int j=0;j<MAXS;j++)            {                if(trans[now][j])                    subamo[now]+=subamo[trans[now][j]];            }        }    }    void deal(int k)    {        int now=this->st;        string s="";        while(k&&now)        {            for(int i=0;i<MAXS;i++)            {                if(trans[now][i])                {                    int to=trans[now][i];                    if(subamo[to]>=k)                    {                        s.push_back('a'+i);                        now=to;                        k--;                        break;                    }                    else                    {                        k-=subamo[to];                    }                }            }        }        printf("%s\n", s.c_str());    }}sam;char s[MAXL];int main(){    scanf("%s", s);int n=strlen(s);    sam.init();    sam.addstring(s, n);    sam.prepare();    int q;scanf("%d", &q);    while(q--)    {        int k;scanf("%d", &k);        sam.deal(k);    }    //system("pause");    return 0;}
阅读全文
0 0
原创粉丝点击