hdu 6096 String(AC自动机)

96 篇文章 0 订阅
30 篇文章 0 订阅

转换还是比较巧妙的。

因为要求前缀后缀都包含的个数,所以可以把字符串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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值