codeforces 235C Cyclical Quest(后缀自动机)

题目链接:http://codeforces.com/contest/235/problem/C

题意:给出两个串S和T,问S有多少个长度为len(T)的子串s,使得s截成两半交换位置后得到的串是T?

思路:将S建立自动机,将两个T接在一起得到T'。在自动机上跑T'。自动机的每个节点记录这个串出现的次数。

 
   




const int KIND=26;

struct SAM

{

    SAM *son[KIND],*pre;

    int len,cnt,flag;

};



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

int d[N],cnt,f[N],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;

    }

}





int main()

{

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

    int i,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=head;

    FOR0(i,len)

    {

        x=s[i]-'a';

        p=p->son[x];

        p->cnt=1;

    }

    FORL0(i,cnt-1)

    {

        p=b[i];

        if(p->pre) p->pre->cnt+=p->cnt;

    }

    int L,Q,ans,flag=0;

    RD(Q);

    while(Q--)

    {

        flag++;

        scanf("%s",s);len=strlen(s);

        p=head; L=0; ans=0;

        FOR0(i,len+len)

        {

            if(i>=len) x=s[i-len]-'a';

            else x=s[i]-'a';

            if(p->son[x]) L++,p=p->son[x];

            else

            {

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

                if(!p) L=0,p=head;

                else L=p->len+1,p=p->son[x];

            }

            if(L>=len)

            {

                while(p->pre&&p->pre->len>=len)

                //这个地方为什么要向前找呢

                //因为若p->pre->len>=len,则说明p所在节点向前len的串和

                //p->pre节点向前len的串是一样的

                //从自动机的性质上来看,p节点和p->pre节点是有p->pre->len的公共前缀的

                {

                    p=p->pre;

                    L=p->len;

                }

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

            }

        }

        PR(ans);

    }

    return 0;

}

 
   

  

 
  

你可能感兴趣的:(codeforces)