Prefixes and suffixes SGU - 505

本文介绍了一种利用AC自动机构造字符串匹配的方法,通过将输入字符串进行特殊处理,实现高效查找一组模式串是否为另一组字符串的前缀或后缀。通过具体实例展示了代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给n个字符串 和m个字符串对 问对于每个字符串对 他最多是n里面多少个字符串的前缀和后缀

一道比较基础的AC自动机的题目 简单点说就是重新构造字符串和需要匹配的字符串对

以样例为例:

aaaaa 就改造为aaaaa}aaaaa 中间那个是26个字母之后的一个字符

而字符串对于a aa为例就改造为aa}a

可以看到假设字符串分别是字符串的前缀和后缀的话那么在两者的“}”两边必然是可以匹配的 那么

问题就转化为对于n个字符串和m个字符串 判断n中每个字符串最多包含多少个m中的字符串 这恰好

就是AC自动机的模型。

感谢一位师兄的shared code 代码思路很清晰 非常有帮助

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <bitset>
#include <vector>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define maxn 222222
vector<int>v;
char a[maxn],pre[maxn],suf[maxn],buf[maxn];
int ans[maxn],num[maxn];
int n,m,be[maxn];
struct ato
{
    int fail[maxn],end[maxn],val[maxn];
    int next[maxn][28];
    int root,L;
    int newnode()
    {
        for(int i=0;i<27;i++) next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void ini()
    {
        L=0;
        root=newnode();
    }
    void insert(int id)
    {
        int len=strlen(buf);
        int now=root;
        for(int i=0;i<len;i++)
        {
            if(next[now][buf[i]-'a']==-1)
            {
                next[now][buf[i]-'a']=newnode();
            }
            now=next[now][buf[i]-'a'];
        }
        ans[id]=now;
        end[now]++;
    }
    void build()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<27;i++)
        {
            if(next[root][i]==-1)
            {
                next[root][i]=root;
            }
            else
            {
                fail[next[root][i]]=root;
                q.push(next[root][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            v.push_back(now);
            q.pop();
            for(int i=0;i<27;i++)
            {
                if(next[now][i]==-1)
                {
                    next[now][i]=next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    q.push(next[now][i]);
                }
            }
        }
    }
    void query()
    {
        int len=strlen(buf);
        int now=root;
        for(int i=0;i<len;i++)
        {
            now=next[now][buf[i]-'a'];
            num[now]++;
        }
    }
    void work()
    {
        int len=v.size()-1;
        for(int i=len;i>=0;i--)
        {
            num[fail[v[i]]]+=num[v[i]];
        }
    }

}ac;
int main()
{
    ac.ini();
    scanf("%d",&n);
    int now=0;
    for(int i=1;i<=n;i++)
    {
        be[i]=now;
        scanf("%s",a+now);
        while(a[now]) now++;
    }
    be[n+1]=now;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s%s",pre,suf);
        int len=strlen(suf);
        int len1=strlen(pre);
        int cnt=0;
        for(int j=0;j<len;j++)
        {
            buf[cnt++]=suf[j];
        }
        buf[cnt++]='z'+1;
        for(int j=0;j<len1;j++)
        {
            buf[cnt++]=pre[j];
        }
        buf[cnt]='\0';
        ac.insert(i);
    }
    ac.build();
    for(int i=1;i<=n;i++)
    {
        int cnt=0;
        for(int j=be[i];j<be[i+1];j++)
        {
            buf[cnt++]=a[j];
        }
        buf[cnt++]='z'+1;
        for(int j=be[i];j<be[i+1];j++)
        {
            buf[cnt++]=a[j];
        }
        buf[cnt]='\0';
        //cout<<buf<<endl;
        ac.query();
    }
    ac.work();
    for(int i=1;i<=m;i++) printf("%d\n",num[ans[i]]);
}
/*
1
abcdefcd
3
ab cd
a cd
ad cd
0
0
0
3
ascblkjklj
dklfjdklfj
sldjfkl
5
asc lj
a j
dk jdklfj
dk jj
sss lll
0
1
1
0
0
*/


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值