• HDU 2846 (AC自动机+多文本匹配)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846

    题目大意:有多个文本,多个模式串。问每个模式串中,有多少个文本?(匹配可重复)

    解题思路

    传统AC自动机是计算单个文本中,模式串出现次数。

    这里比较特殊,每个文本需要单独计算,而且每个匹配在每个文本中只能计数1次。

    比如add,d只能计数1次,而不是;两次。

    所以循环逐个对文本Find。每个Find里,进行Hash,保证每个匹配串只计数1次。

    由于匹配串可重复,在Insert之前,也需要离散化Hash一下,把重复的下标,指向最先插入的下标。

    另外,本题会卡掉不正确AC自动机模板( Find里要写成While(last!=root)而不是While(last->cnt)  )

    代码

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include "cstdio"
    #include "cstring"
    #include "string"
    #include "iostream"
    #include "queue"
    #include "vector"
    #include "algorithm"
    #include "map"
    using namespace std;
    #define maxn 26
    int ans[100005],mt[100005];
    string P[10005];
    struct Trie
    {
        Trie *next[maxn],*fail;
        int cnt;
    }*root;
    Trie *newnode()
    {
        Trie *ret=new Trie;
        memset(ret->next,0,sizeof(ret->next));
        ret->fail=0;
        ret->cnt=0;
        return ret;
    }
    void init() {root=newnode();}
    void Insert(string str,int index)
    {
        Trie *pos=root;
        for(int i=0;i<str.size();i++)
        {
            int c=str[i]-'a';
            if(!pos->next[c]) pos->next[c]=newnode();
            pos=pos->next[c];
        }
        pos->cnt=index;
    }
    void getfail()
    {
        queue<Trie *> Q;
        for(int c=0;c<maxn;c++)
        {
            if(root->next[c])
            {
                root->next[c]->fail=root;
                Q.push(root->next[c]);
            }
            else root->next[c]=root;
        }
        while(!Q.empty())
        {
            Trie *x=Q.front();Q.pop();
            for(int c=0;c<maxn;c++)
            {
                if(x->next[c])
                {
                    x->next[c]->fail=x->fail->next[c];
                    Q.push(x->next[c]);
                }
                else x->next[c]=x->fail->next[c];
            }
        }
    }
    void Find(string str)
    {
        map<int,int> Hash;
        Trie *pos=root,*last;
        for(int i=0;i<str.size();i++)
        {
            int c=str[i]-'a';last;
            if(c<0||c>maxn) {pos=root;continue;}
            if(pos->next[c])
            {
                pos=pos->next[c];
                last=pos;
                while(last!=root)
                {
                    if(!Hash.count(last->cnt))
                    {
                        ans[last->cnt]++;
                        Hash[last->cnt]++;
                    }
                    last=last->fail;
                }
            }
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        int n,m,s;
        string tmp;
        while(cin>>n)
        {
            map<string,int> ms;
            memset(ans,0,sizeof(ans));
            memset(mt,0,sizeof(mt));
            init();
            for(int i=1;i<=n;i++) cin>>P[i];
            cin>>s;
            for(int i=1;i<=s;i++)
            {
                cin>>tmp;
                if(!ms.count(tmp))
                {
                    Insert(tmp,i);
                    ms[tmp]=i;
                    mt[i]=i;
                }
                else mt[i]=ms[tmp];
            }
            getfail();
            for(int i=1;i<=n;i++) Find(P[i]);
            for(int i=1;i<=s;i++) cout<<ans[mt[i]]<<endl;
        }
    }

     

  • 相关阅读:
    [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解
    [译]:Xamarin.Android开发入门——Hello,Android Multiscreen快速上手
    [译]:Xamarin.Android开发入门——Hello,Android深入理解
    [译]:Xamarin.Android开发入门——Hello,Android快速上手
    [译]:Orchard入门——使用标签管理内容
    [译]:Orchard入门——部件管理
    swift UITableView cell自适应高度
    设置Launch Image 启动图片(Xcode7)
    APNs 远程推送
    KVO (Key-Value-Observer, 键值观察)
  • 原文地址:https://www.cnblogs.com/neopenx/p/4533276.html
Copyright © 2020-2023  润新知