• AC自动机,知识点+hdu模板题


    hdu2896

    hdu3065


    对于AC自动机的理解,转载注明出自bestsort.cn  说得贼棒,图文并茂


    自己的模板

     1 int trie[maxn][27];
     2 int cntword[maxn];
     3 int fail[maxn];
     4 int cnt=1;
     5 void add(char *s){
     6     it root = 0,l=strlen(s);
     7     for(it i=0;i<l;i++){
     8         int next =s[i]-'A';
     9         if(!trie[root][next])
    10             trie[root][next] = cnt++;
    11         root = trie[root][next];
    12     }
    13     cntword[root]++;//这里没有重复
    14 }
    15 void getFail(){
    16     queue <int>q;
    17     for(it i=0;i<26;i++){
    18         if(trie[0][i]){
    19             fail[trie[0][i]] = 0;
    20             q.push(trie[0][i]);
    21         }
    22     }
    23     while(!q.empty()){
    24         int now = q.front();
    25         q.pop();
    26         for(int i=0;i<26;i++){
    27             if(trie[now][i]){
    28                 fail[trie[now][i]] = trie[fail[now]][i];
    29                 q.push(trie[now][i]);
    30             }
    31             else
    32                 trie[now][i] = trie[fail[now]][i];
    33         }
    34     }
    35 }
    36 int query(char *s){
    37     int now = 0,ans = 0,l=strlen(s);
    38     for(it i=0;i<l;i++){
    39         if(s[i]<'A' ||s[i]>'Z'){now=0;continue;}//如果字符串有不是A~Z的now归零
    40         now = trie[now][s[i]-'A'];
    41         for(it j=now;j && cntword[j]!=-1;j=fail[j]){
    42             cntword[j]=-143             ans++;//出现过的字符串,标记
    44         }
    45     }
    46     return ans;
    47 }

    hdu2896 病毒侵袭(模板题)

    题意:

    输入n个字符串(n<=500),这n个字符串是指病毒,字符串长度不超过200,字符是ASCII码可见字符.

    给m个字符串(长度不超过1e5)表示网址(m<=1000),说这个网址会有多少病毒,最后统计有多少带病毒的网址

    样例输入                                                      样例输出

    3                                                                   web 1: 1 2 3
    aaa                                                               total: 1             
    bbb
    ccc
    2
    aaabbbccc
    bbaacc

     思路:

    因为字符是ASCII码可见字符,所以字符范围128,tire长度[200*500][128],用cntword标记病毒序号。

    这题hduG++,mle到自闭,然后换了C++就过了,毒毒毒毒瘤。

    #include<iostream>
    #include<map>
    #include<set>
    #include<queue>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define il inline
    #define it register int
    #define inf 0x3f3f3f3f
    #define lowbit(x) (x)&(-x)
    #define pii pair<int,int>
    #define mak(n,m) make_pair(n,m)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mod 998244353
    const int maxn=1e5+10;
    int trie[maxn][128];
    int cntword[maxn];
    int fail[maxn];
    int cnt=0,tot=0,num=1;
    map<char,int>mp;
    void add(char *s,int num1){
        it root = 0,l=strlen(s);
        for(it i=0;i<l;i++){
            int next =mp[s[i]];
            if(next==0){next=num;
                mp[s[i]]=num++;
            }
            if(!trie[root][next])
                trie[root][next] = ++cnt;
            root = trie[root][next];
        }
        cntword[root]=num1;
    }
    void getFail(){
        queue <int>q;
        for(it i=1;i<=num;i++){
            if(trie[0][i]){
                fail[trie[0][i]] = 0;
                q.push(trie[0][i]);
            }
        }
        while(!q.empty()){
            int now = q.front();
            q.pop();
            for(int i=1;i<=num;i++){
                if(trie[now][i]){
                    fail[trie[now][i]] = trie[fail[now]][i];
                    q.push(trie[now][i]);
                }
                else
                    trie[now][i] = trie[fail[now]][i];
            }
        }
    }
    void query(char *s,int num1){
        int now = 0,ans = 0,l=strlen(s);
        set<int>st;
        for(it i=0;i<l;i++){
            now = trie[now][mp[s[i]]];
            for(it j=now;j && cntword[j]!=-1;j=fail[j]){
                st.insert(cntword[j]);
                //cntword[j] = -1;
            }
        }
        if(st.size()){tot++;
            printf("web %d:",num1);
            for(auto &i:st){
                printf(" %d",i);
            }
            printf("
    ");
        }
    }
    char s[10010],ss[210];
    int main(){
        int n,m;mem(cntword,-1);
        scanf("%d",&n);
        for(it i=1;i<=n;i++){
            scanf("%s",ss);
            add(ss,i);
        }
        getFail();
        scanf("%d",&m);
        for(it i=1;i<=m;i++){
            scanf("%s",s);
            query(s,i);
        }
        printf("total: %d
    ",tot);
        return 0;
    }

    hdu3065 病毒侵袭持续中(模板题)

    题意:

    给n个A~Z字符串,字符串长度不超过50(n<=1000),再给一个字符串长度2000000的,里面的字符是ASCII码可见字符,问n出现过几次

    样例输入                                                    样例输出

    3                                                                AA: 2

    AA                                                             CC: 1

    BB

    CC

    ooxxCC%dAAAoen....END

    思路:

    模板套一套,但问题是tire[50*1000][26]是re…,要[1e5][26]

    #include<iostream>
    #include<map>
    #include<set>
    #include<queue>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define il inline
    #define it register int
    #define inf 0x3f3f3f3f
    #define lowbit(x) (x)&(-x)
    #define pii pair<int,int>
    #define mak(n,m) make_pair(n,m)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mod 998244353
    const int maxn=1e5+10;
    int trie[maxn][27];
    int cntword[maxn];
    int fail[maxn];
    int cnt=0,tot=0,n;
    void add(char *s,int num1){
        it root = 0,l=strlen(s);
        for(it i=0;i<l;i++){
            int next =s[i]-'A';
            if(!trie[root][next])
                trie[root][next] = ++cnt;
            root = trie[root][next];
        }
        cntword[root]=num1;
    }
    void getFail(){
        queue <int>q;
        for(it i=0;i<26;i++){
            if(trie[0][i]){
                fail[trie[0][i]] = 0;
                q.push(trie[0][i]);
            }
        }
        while(!q.empty()){
            int now = q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(trie[now][i]){
                    fail[trie[now][i]] = trie[fail[now]][i];
                    q.push(trie[now][i]);
                }
                else
                    trie[now][i] = trie[fail[now]][i];
            }
        }
    }
    char s1[2000010],ss[1010][55];
    void query(char *s){
        int now = 0,ans = 0,l=strlen(s);
        int numm[1010]={0};
        for(it i=0;i<l;i++){
            if(s[i]<'A' ||s[i]>'Z'){now=0;continue;}
            now = trie[now][s[i]-'A'];
            for(it j=now;j && cntword[j]!=-1;j=fail[j]){
                numm[cntword[j]]++;
               //cout<<cntword[j]<<endl;
            }
        }
        for(it i=1;i<=n;i++){
            if(numm[i]==0){continue;}
            printf("%s: %d
    ",ss[i],numm[i]);
        }
    }
    
    int main(){
        while(~scanf("%d",&n)){
        mem(cntword,-1);mem(trie,0);
        for(it i=1;i<=n;i++){
            scanf("%s",ss[i]);
            add(ss[i],i);
        }
        getFail();
        scanf("%s",s1);
        query(s1);
        }
        return 0;
    }

    对了对了还有一个hdu2222,我用tire树莽过的题

    这里就贴一个代码吧

    #include<queue>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<cmath>
    #include<string>
    #include<vector>
    #include<functional>
    #pragma warning(disable:4996)
    using namespace std;
    const int maxn = 1000010;
    #define inf 0x3f3f3f3f
    #define mem(k,b) memset(k,b,sizeof(k))
    #define ll long long
    char s[maxn];
    char ss[55];
    int k = 1, t, n;
    int g[240000][26] = { 0 }, vis[240000] = { 0 };
    inline void insert(char *w){
        int p = 0, l = strlen(w);
        for (int i = 0; i < l; i++){
            int c = w[i] - 'a';
            if (!g[p][c]){
                g[p][c] = k++;
            }
            p = g[p][c];
        }
        vis[p]++;
        return;
    }
    inline int search(char *w){
        int l = strlen(w);
        int sum = 0;
        for (int j = 0; j < l; j++){
            int p = 0;
            for (int i = j; i < j + 50; i++){
                if (i == l){
                    break;
                }
                int c = w[i] - 'a';
                if (!g[p][c]){
                    break;
                }
                p = g[p][c];
                if (vis[p]){
                    sum += vis[p];
                    vis[p] = 0;
                }
            }
        }
        return sum;
    }
    int main()
    {
        scanf("%d", &t);
        while (t--){
            k = 1; mem(vis, 0); mem(g, 0);
            scanf("%d", &n);
            getchar();
            for (int i = 0; i < n; i++){
                gets(ss);
                insert(ss);
            }
            gets(s);
            printf("%d
    ", search(s));
    
        }
        return 0;
    }
  • 相关阅读:
    方法引用
    day2
    柯朗数(Courant number)研究
    Socket网络编程学习一
    自制导航
    HighChart 体验之旅 (后台传递JSON参数和数据的方法)
    HighChart体验之旅2 对HighChart控件的再次封装
    委托学习小计
    面试常用SQL整理
    动态LINQ(Lambda表达式)构建
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/12466391.html
Copyright © 2020-2023  润新知