zoukankan      html  css  js  c++  java
  • SPOJ8093Sevenk Love Oimaster(广义后缀自动机)

     Oimaster and sevenk love each other.

        But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman's nature, sevenk felt angry and began to check oimaster's online talk with ChuYuXun.    Oimaster talked with ChuYuXun n times, and each online talk actually is a string.Sevenk asks q questions like this,    "how many strings in oimaster's online talk contain this string as their substrings?"
     
    Input
     
    There are two integers in the first line, 
    the number of strings n and the number of questions q.
    And n lines follow, each of them is a string describing oimaster's online talk. 
    And q lines follow, each of them is a question.
    n<=10000, q<=60000 
    the total length of n strings<=100000, 
    the total length of q question strings<=360000
     
    Output
    For each question, output the answer in one line.
    Sample Input
    3 3
    abcabcabc
    aaa
    aafe
    abc
    a
    ca
    Sample Output
    1
    3
    1

    题意:

    给定一些模板串,询问每个匹配串在多少个模板串里出现过。

    思路:

         后缀数组办法:

           全部模板串连接在一起SA排序,SA数组附件的串里面去验证原串,还没写,我说不清楚,大概是后缀数组+RMQ处理。

          后缀自动机办法:

           1,广义后缀自动机+dfs序列+。。。

           2,后缀自动机+标记,对于每个新的后缀集合np,标记它最近出现的原串,对每个模板串出现的新串的数量++。(目前发现最快的版本,如下)

    经验:

    • 与普通的后缀自动机不同的是,广义后缀自自动机在加入一个新串的时候,从root开始。
    • 为了记录每个状态在哪些串出现过,会在每个np向上传递,我的代码是用的没加一个字符,向上传递一次。也可以用bitset记录在哪里出现过等到加完所有字符串后再拓扑排序,然后“亦或”向上传递。
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define N 200003
    using namespace std;
    int ch[N][30],fa[N],l[N],n,m,len;
    int r[N],v[N],cnt,np,p,nq,q,last,root,nxt[N],now,size[N];
    char s[N];
    void extend(int x)
    {
        int c=s[x]-'a';
        p=last; np=++cnt; last=np; 
        l[np]=l[p]+1;
        for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if (!p) fa[np]=root;
        else {
            q=ch[p][c];
            if (l[q]==l[p]+1) fa[np]=q;
            else {
                nq=++cnt; l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[nq]); size[nq]=size[q]; nxt[nq]=nxt[q];
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        for (;np;np=fa[np]) 
         if (nxt[np]!=now) {
             size[np]++;
             nxt[np]=now;
         }
         else break;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        root=++cnt;
        for(int i=1;i<=n;i++) {
            scanf("%s",s+1);
            last=root;
            len=strlen(s+1);
            now=i;
            for (int j=1;j<=len;j++) 
             extend(j);
        }
        for (int i=1;i<=m;i++) {
            scanf("%s",s+1);
            len=strlen(s+1);
            p=root;
            for (int j=1;j<=len;j++)  p=ch[p][s[j]-'a'];
            printf("%d
    ",size[p]);
        }
    }
  • 相关阅读:
    用一个测试类简化排序算法时间复杂度的研究
    用斗地主的实例学会使用java Collections工具类
    数据结构:用实例分析ArrayList与LinkedList的读写性能
    用一个通俗易懂的例子彻底说清楚单例模式
    用自定义链式栈解决力扣括号匹配问题
    数据结构之链式队列的代码实现及有趣应用
    用非常硬核的JAVA序列化手段实现对象流的持久化保存
    SpringBoot整合SpringSecurity实现JWT认证
    六百字搞懂lambda
    判空我推荐StringUtils.isBlank
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8024294.html
Copyright © 2011-2022 走看看