SPOJ 8222 Substrings(后缀自动机)

题目链接:http://www.spoj.com/problems/NSUBSTR/

题意:给定一个串S,定义函数f(x)表示长度为x的所有子串中出现次数最多的子串出现的次数。输出f(i)(1<=i<=len(S))。

思路:建立串S的后缀自动机。然后就是对于每个节点u,从u开始到达接收状态的路径的个数就是u节点对应串的出现次数。







const int KIND=26;

struct SAM

{

    SAM *son[KIND],*pre;

    int len,cnt;



    void init()

    {

        clr(son,NULL);

        pre=NULL;

        len=0;

    }

};



SAM sam[N],*head,*last,*b[N];

int d[N],cnt,f[N],len;

char s[N];



void initSAM()

{

    sam[0].init();

    head=last=&sam[0];

    cnt=1;

}





void insert(int x)

{

    SAM *p=&sam[cnt++],*u=last;

    p->len=last->len+1;

    last=p;

    for(;u&&!u->son[x];u=u->pre) u->son[x]=p;

    if(!u) p->pre=head;

    else if(u->son[x]->len==u->len+1) p->pre=u->son[x];

    else

    {

        SAM *r=&sam[cnt++],*q=u->son[x];

        *r=*q; r->len=u->len+1;

        p->pre=q->pre=r;

        for(;u&&u->son[x]==q;u=u->pre) u->son[x]=r;

    }

}



int main()

{

    RD(s);

    len=strlen(s);

    initSAM();

    int i;

    FOR0(i,len) insert(s[i]-'a');

    FOR0(i,cnt) d[sam[i].len]++;

    FOR1(i,len) d[i]+=d[i-1];

    FOR0(i,cnt) b[--d[sam[i].len]]=&sam[i];

    last=head;

    FOR0(i,len)

    {

        last=last->son[s[i]-'a'];

        last->cnt=1;

    }

    FORL1(i,cnt-1)

    {

        f[b[i]->len]=max(f[b[i]->len],b[i]->cnt);

        b[i]->pre->cnt+=b[i]->cnt;

    }

    FORL1(i,len-1) f[i]=max(f[i],f[i+1]);

    FOR1(i,len) PR(f[i]);

    return 0;



}

  

你可能感兴趣的:(substring)