• 【字符串】hdu5880 ac自动机模板


    ac自动机:

    给你若干个单词,判断一段文字里边这些单词出现了吗,在哪出现,出现几次?

    首先是字典树模板:

    #include<bits/stdc++.h>
    #define debug printf("!");
    using namespace std;
    const int maxn=1e3+50;
    struct trie_node{
        int count;
        trie_node*son[26];
    };
    trie_node* new_node()
    {
        trie_node* pnode=new trie_node();
        pnode->count=0;
        for(int i=0;i<26;i++)pnode->son[i]=NULL;
        return pnode;
    }
    void trie_insert(trie_node *root,char key[])
    {
        trie_node* node=root;
        char *p=key;
        while(*p)
        {
            if(node->son[*p-'a']==NULL)node->son[*p-'a']=new_node();
            node=node->son[*p-'a'];
            ++p;
        }
        node->count+=1;
    }
    int trie_search(trie_node *root,char key[])
    {
        trie_node*node=root;
        char *p=key;
        while(*p&&node!=NULL)
        {
            node=node->son[*p-'a'];
            ++p;
        }
        if(node==NULL)return 0;
        else return node->count;
    }
    
    int main()
    {
        int n,q,i,j;
        char s[20];
        trie_node *root;
        root=new_node();
        scanf("%d%d",&n,&q);
        while(n--)
        {
            scanf("%s",s);
            trie_insert(root,s);
        }
        while(q--)
        {
            scanf("%s",s);
            printf("%d
    ",trie_search(root,s));
        }
    }
    View Code

    时隔几个月,觉得上面那个模板好丑,搬了oiwiki的板子:

    struct trie {
      int nex[100000][26], cnt;
      bool exist[100000];  // 该结点结尾的字符串是否存在
    
      void insert(char *s, int l) {  // 插入字符串
        int p = 0;
        for (int i = 0; i < l; i++) {
          int c = s[i] - 'a';
          if (!nex[p][c]) nex[p][c] = ++cnt;  // 如果没有,就添加结点
          p = nex[p][c];
        }
        exist[p] = 1;
      }
      bool find(char *s, int l) {  // 查找字符串
        int p = 0;
        for (int i = 0; i < l; i++) {
          int c = s[i] - 'a';
          if (!nex[p][c]) return 0;
          p = nex[p][c];
        }
        return exist[p];
      }
    };
    View Code

    然后是ac自动机:字典树+fail指针 重点在getfail函数

    例题是 hdu5880

    一整天,一直被卡MLE,改成指针形式的动态开点也卡。

    然后去搜,终于搜到一篇博客。

    博客说:不要一次性memset,而是,用到一个点,memset一次。 

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #define debug printf("!");
    using namespace std;
    const int maxn=1e6+5;
    struct T{
        int fail;
        int vis[26];
        int dep;
    }ac[maxn];
    
    int cnt;
    
    char s[maxn];
    
    void init(int t)
    {
        ac[t].fail=ac[t].dep=0;
        memset(ac[t].vis,0,sizeof(ac[t].vis));
    }
    
    
    inline void insert(char *s)
    {
        int len=strlen(s),i,p=0,dep=0;
        for(i=0;i<len;i++)
        {
            dep++;
            if(!ac[p].vis[s[i]-'a'])
            {
                ac[p].vis[s[i]-'a']=++cnt;
                init(cnt);
            }
            p=ac[p].vis[s[i]-'a'];
        }
        ac[p].dep=dep;
    }
    inline void get_fail()
    {
        queue<int>que;
        for(int i=0;i<26;i++)
        {
            if(ac[0].vis[i])
            {
                ac[ac[0].vis[i]].fail=0;
                que.push(ac[0].vis[i]);
            }
        }
        while(!que.empty())
        {
            int u=que.front();
            que.pop();
            for(int i=0;i<26;i++)
            {
                if(ac[u].vis[i]!=0)
                {
                    ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];
                    que.push(ac[u].vis[i]);
                }
                else ac[u].vis[i]=ac[ac[u].fail].vis[i];
            }
        }
    }
    void query(char s[])
    {
        int len=strlen(s),i,j,k,t=0,p=0;
        for(i=0;i<len;i++)
        {
            char c=s[i];
            if('A'<=c&&c<='Z')c+=32;
            else if(!('a'<=c&&c<='z'))
            {
                p=0;continue;
            }
            p=ac[p].vis[c-'a'];
            for(j=p;j;j=ac[j].fail)
            {
                if(ac[j].dep)
                {
                    for(k=i-ac[j].dep+1;k<=i;k++)s[k]='*';
                }
            }
        }
    }
    int main()
    {
        int n,T;
        scanf("%d",&T);
        while(T--)
        {
            cnt=0;
            init(0);
            scanf("%d",&n);
            while(n--)
            {
                scanf("%s",s);
                insert(s);
            }
            get_fail();
            getchar();
            cin.getline(s,maxn);
            query(s);
            printf("%s
    ",s);
        }
    }
    View Code

    (上面的板子也不好看●﹏●   用下面的:

    例题: 破忒头的匿名信

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=5e5+5;
    
    ll f[maxn];
    int val[maxn],dep[maxn];
    struct AC{
        int tr[maxn][26],cnt;
        int fail[maxn];
        void insert(char s[],int len,int w)
        {
            int p=0;
            for(int i=0;i<len;i++)
            {
                if(!tr[p][s[i]-'a'])tr[p][s[i]-'a']=++cnt;
                p=tr[p][s[i]-'a'];
            }
            dep[p]=len;
            if(!val[p])val[p]=w;
            val[p]=min(val[p],w);
        }
        void getfail()
        {
            queue<int>que;
            for(int i=0;i<26;i++)if(tr[0][i])que.push(tr[0][i]);
            while(!que.empty())
            {
                int p=que.front();que.pop();
                for(int i=0;i<26;i++)
                {
                    if(tr[p][i])fail[tr[p][i]]=tr[fail[p]][i],que.push(tr[p][i]);
                    else tr[p][i]=tr[fail[p]][i];
                }
            }
        }
        void query(char s[],int len)
        {
            int j,p=0;
            for(int i=1;i<=len;i++)
            {
                j=p=tr[p][s[i]-'a'];
                while(j)
                {
                    if(dep[j])f[i]=min(f[i],f[i-dep[j]]+val[j]);
                    j=fail[j];
                }
            }
        }
    }ac;
    char s[maxn];
    int main()
    {
        int n,w,len;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s%d",s,&w);
            ac.insert(s,strlen(s),w);
        }
        ac.getfail();
        scanf("%s",s+1);
        len=strlen(s+1);
        for(int i=1;i<=len;i++)f[i]=1e16;
        ac.query(s,len=strlen(s+1));
        printf("%lld
    ",f[len]==1e16?-1:f[len]);
    }
    View Code
  • 相关阅读:
    Balanced Number [ZOJ 3416]
    动态树
    Jason的特殊爱好 [FZU 2113]
    Raney引理
    Tri Tiling [POJ 2663]
    糖尿病的虾青素+胰岛素疗法 (转)
    JAVASCRIPT 开发工具:aptana ,WebStorm
    众志和达,英文SOUL 存储与数据安全提供商
    健身音乐及其它
    nodejs + CompoundJS 资源
  • 原文地址:https://www.cnblogs.com/kkkek/p/11726736.html
Copyright © 2020-2023  润新知