zoukankan      html  css  js  c++  java
  • Gym 101741 K(AC自动机)

    传送门

    题意:

    给你一个长度为nn的模式串以及mm个总长度长度不超过10510^5的匹配串。问这mm个匹配串分别在模式串中出现了多少次,要求每一次出现位置不能够相交。

    题目分析:

    首先,我们要知道,虽然匹配串的总长度为10510^5,但是因为KMP的时间复杂度为O(n+m)mathcal{O}(n+m),这就使得整体复杂度总会变成O(n2)mathcal{O}{(n^2)},因此KMP显然是会超时的。

    因为涉及多串匹配的问题,因此我们可以往AC自动机方向去考虑。我们首先离线将询问的所有字符串建立出AC自动机,之后我们只需要用模式串在AC自动机上去匹配即可。

    但是该问题的特殊点在于:两个能够在模式串中匹配的串不能够有相交部分。对于这一点,我们只需要在普通的查询中进行修改;我们需要记录一下在AC自动机匹配到字符串strstr(我们设该状态在自动机上的ididii)的位置pos(i)pos(i),以及strstr前一个被匹配了的位置lastpos(i)lastpos(i)。我们可以发现,如果当前匹配的位置与之前匹配之差小于当前字符串的长度str|str|,即pos(i)lastpos(i)>=strpos(i)-lastpos(i)>=|str|则说明在当前位置pos(i)pos(i)下,能够对答案有贡献,我们使该匹配串的答案加11即可。

    最后我们只需要维护一下匹配串的终点位置,最后输出答案即可。

    代码:

    #include <bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    char st[maxn],st1[maxn];
    struct Trie{
        int next[maxn<<2][26],End[maxn<<2],root,fail[maxn<<2],id;
        int cnt[maxn<<2],last[maxn<<2],Len[maxn<<2];
        int newnode(){
            for(int i=0;i<26;i++){
                next[id][i]=-1;
            }
            Len[id]=0;
            return id++;
        }
        void init(){
            id=0;
            root=newnode();
        }
        void Insert(char *str,int id){
            int len=strlen(str);
            int now=root;
            for(int i=0;i<len;i++){
                if(next[now][str[i]-'a']==-1)
                    next[now][str[i]-'a']=newnode();
                Len[next[now][str[i]-'a']]=Len[now]+1;
                now=next[now][str[i]-'a'];
            }
            End[id]=now;
            Len[now]=len;
        }
        void build(){
            queue<int>que;
            int now=root;
            fail[root]=root;
            for(int i=0;i<26;i++){
                if(next[root][i]==-1){
                    next[root][i]=root;
                }
                else{
                    fail[next[root][i]]=root;
                    que.push(next[root][i]);
                }
            }
            while(!que.empty()){
                now=que.front();
                que.pop();
                for(int i=0;i<26;i++){
                    if(next[now][i]==-1)
                        next[now][i]=next[fail[now]][i];
                    else{
                        fail[next[now][i]]=next[fail[now]][i];
                        que.push(next[now][i]);
                    }
                }
            }
        }
        void query(char *str){
            int len=strlen(str);
            for(int i=0;i<id;i++) cnt[i]=0,last[i]=-1;
            int now=root;
            for(int i=0;i<len;i++){
                now=next[now][str[i]-'a'];
                int tmp=now;
                while(tmp!=root){
                    if(i-last[tmp]>=Len[tmp]){
                        cnt[tmp]++;
                        last[tmp]=i;
                    }
                    tmp=fail[tmp];
                }
            }
        }
    }ac;
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        ac.init();
        scanf("%s",st);
        for(int i=1;i<=m;i++){
            scanf("%s",st1);
            ac.Insert(st1,i);
        }
        ac.build();
        ac.query(st);
        for(int i=1;i<=m;i++){
            printf("%d
    ",ac.cnt[ac.End[i]]);
        }
        return 0;
    }
    
  • 相关阅读:
    How to install VXDIAG Honda, Toyota and JLR SDD software
    16% off MPPS V16 ECU tuning tool for EDC15 EDC16 EDC17
    Cummins INSITE locked and ask for verification code
    How to use BMW Multi Tool 7.3 to replace lost key for BMW X1
    Bleed Brake Master Cylinder with Intelligent Tester IT2
    Porsche Piwis Tester II “No VCI has been detected”,how to do?
    Creader VIII VS. Creader VII+
    How to solve GM MDI cannot complete the installation
    汽车OBD2诊断程序开发 (原文转载,思路很清晰!)
    汽车节温器单片机开发思路
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007160.html
Copyright © 2011-2022 走看看