hdu 6096 String(AC自动机)

来源:互联网 发布:昆仑墟麒麟臂升阶数据 编辑:程序博客网 时间:2024/05/22 05:13

转换还是比较巧妙的。

因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca

然后对于一组前缀a后缀b转换成b#a,比如ab ca,就是ca#ab,

然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca#ab满足为abca#abca的一个子串,也就是abca满足这个前缀后缀,所以问题,就转换成了典型的ac自动机匹配问题。

加个#的原因是为了只让后缀#前缀这种串能在AC自动机匹配到。

然后求答案的时候,需要对连接到自己的fail的位置累加一下,含义想一下就明白了。


代码:

#include <bits/stdc++.h>using namespace std;const int maxn=1e6+5+1e5;char str[maxn];char *s[maxn];int d[maxn], pos[maxn], ans[maxn], st[maxn], len[maxn];char s1[maxn], s2[maxn];struct acho{    int nex[maxn+10][29], cnt[maxn+10], fail[maxn+10], match[maxn+10], nl[maxn+10];    int L, root;    int  newnode()    {        for(int i=0; i<27; i++)nex[L][i]=-1;        cnt[L++]=0;        fail[L-1]=0;        return L-1;    }    void init()    {        L=0;        root=newnode();    }    int insert(char *a)    {        int now=root, i;        for(i=0; a[i]; i++)        {            if(nex[now][a[i]-'a']==-1)            {                nex[now][a[i]-'a']=newnode();                nl[L-1]=i+1;            }            now=nex[now][a[i]-'a'];        }        cnt[now]=1;        return now;    }    queue<int>que;    void build()    {        while(que.empty()==0)que.pop();        int now=root;        for(int i=0; i<27; i++)        {            if(nex[now][i]==-1)nex[now][i]=root;            else            {                fail[nex[now][i]]=root;                que.push(nex[now][i]);            }        }        while(que.empty()==0)        {            now=que.front();            que.pop();            for(int i=0; i<27; i++)            {                if(nex[now][i]!=-1)                {                    que.push(nex[now][i]);                    fail[nex[now][i]]=nex[fail[now]][i];                    match[nex[now][i]]=cnt[nex[now][i]]?nex[now][i]:match[nex[fail[now]][i]];                }                else                {                    nex[now][i]=nex[fail[now]][i];                }            }        }        return;    }    void search(char *a, int len)    {        int i, now=root;//        printf("%s\n", a);        for(i=0; a[i]; i++)        {            now=nex[now][a[i]-'a'];            while(nl[now]>len)            {                now=fail[now];            }            ans[match[now]]++;//            printf("%c %d\n", a[i], now);        }    }    void cal()    {        memset(d, 0, sizeof(int)*(L+1));        int j, k=0, i;        for(i=0; i<L; i++)d[fail[i]]++;        for(i=0; i<L; i++)if(!d[i])st[k++]=i;        for(i=0; i<k; i++)        {            j=fail[st[i]];            ans[j]+=ans[st[i]];            if(!(--d[j]))st[k++]=j;        }        return;    }}acho;int main(){    int t, i, j, n, q;    cin>>t;    while(t--)    {        acho.init();        scanf("%d%d", &n, &q);        j=0;        for(i=0; i<n; i++)        {            s[i]=str+j;            scanf("%s", s[i]);            len[i]=strlen(s[i])+1;            j+=len[i];            strcpy(str+j, s[i]);            str[j-1]='z'+1;            j+=len[i];        }        for(i=0; i<q; i++)        {            scanf("%s%s", s1+1, s2);            s1[0]='z'+1;            strcat(s2, s1);            pos[i]=acho.insert(s2);//            printf("%d ", pos[i]);        }//        printf("\n");        acho.build();//        for(i=0; i<acho.L; i++)printf("%d %d\n", i, acho.match[i]);        for(i=0; i<n; i++)        {            acho.search(s[i], len[i]);        }        acho.cal();        for(i=0; i<q; i++)printf("%d\n", ans[pos[i]]);        for(i=0; i<=acho.L; i++)        {            ans[i]=0;            acho.match[i]=0;        }    }    return 0;}


原创粉丝点击