HDU 4436 str 2 int(接尾辞自動機)

2265 ワード

タイトルリンク:http://acm.hdu.edu.cn/showproblem.php?pid=4436
題意:いくつかの数字列が与えられ、各数字列はいくつかの数字に分けることができ、例えば123は1,2,3,12,23123に分けることができる.すべての数字の列の分ける数字の集合の和を求めます.
構想:接尾辞オートマチック:シリアル間を数字10で区切って、オートマチックを確立します.ノードpとデジタルjから得られるサブノードq,q->cnt+=p->cnt,q->sum+=p->sum*10+p->cnt*j.


const int KIND=11;

struct SAM

{

    SAM *son[KIND],*pre;

    int len,sum,cnt;



    void init()

    {

        clr(son,NULL);

        pre=NULL;

        cnt=sum=len=0;

    }

};



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

int d[N];

int cnt,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->init();

    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;

    }

}





void init()

{

    int i;

    FOR0(i,len+1) d[i]=0;

    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];

}





int n;





void deal()

{

    int ans=0,i,j;

    

    SAM *p;

    head->cnt=1;

    FOR0(i,cnt)

    {

        p=b[i];

        ans=(ans+p->sum)%mod;

        FOR0(j,10) if(p->son[j])

        {

            if(!i&&!j) continue;

            (p->son[j]->cnt+=p->cnt)%=mod;

            (p->son[j]->sum+=p->sum*10+p->cnt*j)%=mod;

        }

    }

    PR(ans);

}



int main()

{

    while(scanf("%d",&n)!=-1)

    {

        initSAM(); len=0;

        int i,L;

        while(n--)

        {

            RD(s); L=strlen(s);

            FOR0(i,L) insert(s[i]-'0'),len++;

            insert(10); len++;

        }

        init();

        deal();

    }

    return 0;

}