BUAA 533 nanae 是弱小灰(后缀自动机)

题目链接:http://acm.buaa.edu.cn/problem/533/

题意:给定一个串S和若干串T,求S有多少不同的子串以T中的一个结尾?

思路:将S翻转建立自动机,T翻转匹配。







const int KIND=26;

struct SAM

{

    SAM *son[KIND],*pre;

    int len,flag;

    i64 cnt;

};



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

int d[N],cnt,len;

char s[N];



void initSAM()

{

    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;

    }

}





void reverse(char *s,int len)

{

    int L=0,R=len-1;

    while(L<R) swap(s[L++],s[R--]);

}



void reverse(string &s)

{

    int L=0,R=SZ(s)-1;

    while(L<R) swap(s[L++],s[R--]);

}



string str[1005];







int main()

{

    initSAM(); RD(s); len=strlen(s); reverse(s,len);

    int i,j,x;

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

    SAM *p;

    FOR0(i,cnt) sam[i].cnt=1,sam[i].flag=0;

    FORL0(i,cnt-1)

    {

        p=b[i];

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

        {

            p->cnt+=p->son[j]->cnt;

        }

    }

    i64 ans=0;

    int n,flag;

    RD(n);

    FOR0(i,n) RD(str[i]),reverse(str[i]);

    sort(str,str+n);

    FOR0(i,n)

    {

        p=head; flag=1;

        FOR0(j,SZ(str[i]))

        {

            x=str[i][j]-'a';

            if(p->son[x])

            {

                p=p->son[x]; 

                if(p->flag) flag=0;

            }

            else flag=0;

            if(!flag) break;

        }

        if(flag) ans+=p->cnt,p->flag=1;

    }

    PR(ans);

    return 0;

}

 

你可能感兴趣的:(uaa)