zoukankan      html  css  js  c++  java
  • 2017多校第6场 HDU 6096 String AC自动机

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

    题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数。

    解法:

    因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca

    然后对于一组前缀a后缀b转换成b{a,比如ab ca,就是ca{ab,

    然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca{ab满足为abca{abca的一个子串,也就是abca满足这个前缀后缀,所以问题,就转换成了典型的ac自动机匹配问题。

    加个{的原因是为了只让后缀{前缀这种串能在AC自动机匹配到。

    然后求答案的时候,需要对连接到自己的fail的位置累加一下,含义想一下就明白了。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000010;
    const int maxs = 30;
    string s[maxn];
    int d[maxn],pos[maxn],ans[maxn],st[maxn],len[maxn];
    struct Acautomata{
        int nxt[maxn][maxs],cnt[maxn],fail[maxn],match[maxn],dep[maxn];
        int L, root;
        int newnode(){
            for(int i=0; i<maxs; i++) nxt[L][i]=-1;
            cnt[L++]=0;
            fail[L-1]=0;
            return L-1;
        }
        void init(){
            L = 0;
            root = newnode();
        }
        int Insert(string a){
            int now=root;
            for(int i=0; a[i]; i++){
                if(nxt[now][a[i]-'a']==-1){
                    nxt[now][a[i]-'a']=newnode();
                    dep[L-1]=i+1;
                }
                now=nxt[now][a[i]-'a'];
            }
            cnt[now]=1;
            return now;
        }
        void build()
        {
            queue<int>q;
            int now=root;
            fail[0] = 0;
            for(int i=0; i<maxs; i++){
                if(nxt[now][i]==-1){
                    nxt[now][i]=root;
                    continue;
                }
                else{
                    fail[nxt[now][i]]=root;
                    q.push(nxt[now][i]);
                }
            }
            while(!q.empty())
            {
                now = q.front();
                q.pop();
                for(int i=0; i<maxs; i++){
                    if(nxt[now][i]!=-1){
                        q.push(nxt[now][i]);
                        fail[nxt[now][i]] = nxt[fail[now]][i];
                        match[nxt[now][i]] = cnt[nxt[now][i]]?nxt[now][i]:match[nxt[fail[now]][i]];
                    }else{
                        nxt[now][i] = nxt[fail[now]][i];
                    }
                }
            }
        }
        void solve1(string a, int h){
            int now=root;
            int sz = a.size();
            for(int i=0; i<sz; i++){
                now=nxt[now][a[i]-'a'];
                while(dep[now]>h){
                    now=fail[now];
                }
                ans[match[now]]++;
            }
        }
        void solve2(){//累加答案,对连到自己的fail进行累加求和
            memset(d, 0, sizeof(d));
            int j, k = 0;
            for(int i=0; i<L; i++) d[fail[i]]++;
            for(int i=0; i<L; i++) if(!d[i]) st[k++]=i;
            for(int i=0; i<k; i++){
                j=fail[st[i]];
                ans[j]+=ans[st[i]];
                if(!(--d[j])){
                    st[k++]=j;
                }
            }
        }
    }ZXY;
    int n, q;
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            ZXY.init();
            scanf("%d%d", &n,&q);
            for(int i=0; i<n; i++){
                cin>>s[i];
                len[i] = s[i].size()+1;
                string temp=s[i];
                s[i]+=char('z'+1);
                s[i]+=temp;
            }
            for(int i=0; i<q; i++){
                string s1,s2;
                cin>>s1>>s2;
                s2 = s2 + char('z'+1);
                s2 = s2 + s1;
                pos[i] = ZXY.Insert(s2);
            }
            ZXY.build();
            for(int i=0; i<n; i++){
                ZXY.solve1(s[i],len[i]);
            }
            ZXY.solve2();
            for(int i=0; i<q; i++) printf("%d
    ", ans[pos[i]]);
            for(int i=0; i<=ZXY.L; i++){
                ans[i]=0;
                ZXY.match[i]=0;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    注解
    LeedCode刷题:337.打家劫舍Ⅲ
    计蒜客:踏青(DFS)
    C++中memset()用法
    DFS深度优先搜索(附例题)
    计蒜客:网络交友:map+set+并查集
    JavaString类中valueOf和parseInt的区别
    Leedcode刷题 539. 最小时间差
    ps换衣服颜色
    hashmap的一些总结
  • 原文地址:https://www.cnblogs.com/spfa/p/7352599.html
Copyright © 2011-2022 走看看