zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    iscroll中使用input框的话是导致无法选中input框
    JS中setInterval()和clearInterval()的使用以及注意事项
    连接oracle出现的问题以及解决办法
    Oracle数据库数据显示乱码问题解决方法。
    Android4.4以上Uri转换成绝对路径的工具类
    安卓,调用相机并适配6.0后
    问题-解决
    ORACLE相关
    PL/SQL表结构/数据的导出
    springMVC笔记
  • 原文地址:https://www.cnblogs.com/HooYing/p/12459784.html
Copyright © 2011-2022 走看看