AC自动机模板题

P3808 AC自动机(简单版)

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e6+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
void Insert(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    sum[rt]++;
}
void get_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
int query(string s)
{
    int rt=0,ans=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        for(int k=rt;k&&sum[k]!=-1;k=fail[k])
            ans+=sum[k],sum[k]=-1;
    }
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    string s;
    for(int i=1;i<=n;i++)
        cin>>s,Insert(s);
    get_fail();
    cin>>s;
    printf("%d
",query(s));
    return 0;
}

P3796 AC自动机(加强版)

有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e4+10;
int trie[maxx][26],tot;
int sum[maxx],fail[maxx];
int ans[maxx];
string s[maxx];
void Insert(string s,int x)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    sum[rt]=x;
}
void get_fail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])fail[trie[u][i]]=trie[fail[u]][i],q.push(trie[u][i]);
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
void query(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        for(int k=rt;k;k=fail[k])ans[sum[k]]++;
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        tot=0;
        memset(trie,0,sizeof(trie));
        memset(sum,0,sizeof(sum));
        memset(fail,0,sizeof(fail));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++)
            cin>>s[i],Insert(s[i],i);
        get_fail();
        string t;
        cin>>t;
        query(t);
        int tmp=0;
        for(int i=1;i<=n;i++)tmp=max(tmp,ans[i]);
        printf("%d
",tmp);
        for(int i=1;i<=n;i++)
            if(ans[i]==tmp)cout<<s[i]<<endl;
    }
    return 0;
}

P5357 AC自动机(二次加强版)

给你一个文本串 S 和 n 个模式串 T1...Tn,请你分别求出每个模式串Ti 在 S 中出现的次数。

拓扑建图优化

#include<bits/stdc++.h>
using namespace std;
const int maxx = 2e5+10;
int trie[maxx][26],tot;
int fail[maxx],vis[maxx];
int in[maxx],ma[maxx],sum[maxx],ans[maxx];
void Insert(string s,int x)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        if(!trie[rt][id])trie[rt][id]=++tot;
        rt=trie[rt][id];
    }
    if(!vis[rt])vis[rt]=x;
    ma[x]=vis[rt]; //重复单词
}
void getfail()
{
    queue<int>q;
    for(int i=0;i<26;i++)
        if(trie[0][i])fail[trie[0][i]]=0,q.push(trie[0][i]);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[u][i])
            {
                fail[trie[u][i]]=trie[fail[u]][i];
                in[fail[trie[u][i]]]++;
                q.push(trie[u][i]);
            }
            else trie[u][i]=trie[fail[u]][i];
        }
    }
}
void query(string s)
{
    int rt=0;
    for(int i=0;i<s.size();i++)
    {
        int id=s[i]-'a';
        rt=trie[rt][id];
        sum[rt]++;
    }
}
void topu()
{
    queue<int>q;
    for(int i=0;i<=tot;i++)
        if(in[i]==0)q.push(i);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        ans[vis[u]]=sum[u];
        int v=fail[u];
        in[v]--;
        sum[v]+=sum[u];
        if(in[v]==0)q.push(v);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    string s;
    for(int i=1;i<=n;i++)
        cin>>s,Insert(s,i);
    getfail();
    cin>>s;
    query(s);
    topu();
    for(int i=1;i<=n;i++)
        printf("%d
",ans[ma[i]]);
    return 0;
}
原文地址:https://www.cnblogs.com/HooYing/p/12459784.html