zoukankan      html  css  js  c++  java
  • bzoj 3277 串 && bzoj 3473 字符串 && bzoj 2780 [Spoj]8093 Sevenk Love Oimaster——广义后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277

       https://www.lydsy.com/JudgeOnline/problem.php?id=3473

    学习的博客:https://www.cnblogs.com/HocRiser/p/9580478.html

    广义后缀自动机有两种写法,这里写的是 trie 树的那种。

    大意就是每个串从自动机的根开始走,

    1.如果存在 q = go[p][w] ,且 l [q] == l [p]+1 ,  那么直接把 q 看作这次插入了的点,下次令 p = q ,续着往后插入;

    2.如果存在 q = go[p][w] ,且 l [q] != l [p]+1 , 那么分出一个 nq 来,把 nq 看作这次插入了的点,下次令 p = nq ,续着往后插入;

    3.如果不存在 q = go[p][w] ,就新建一个 np ;然后就是一个串的后缀自动机插入了;下次令 p = np 。

    要计算后缀自动机上的每个点代表的那些子串在所有串里出现了多少次,记为 ct[ ] ;

      在做一个串的插入的时候,考虑让一些位置的 ct[ ] ++ ;每插入一个字符,就跳 fa ,给所有 fa 的 ct[ ] ++ ;但如果已经被当前字符串的之前字符弄得 ct[ ] 加一过了,就不用再加了;

      不要边建自动机边做 ct[ ] ++ ;因为那时的 parent 树还不是所有串的。

    然后拓扑排序一下,从根到叶子做 dp ,自己节点可以贡献的合法子串个数 ans[ ] 就是 ans[ fa ] 再加上 “ 自己出现了 >= k 次?l [cr] - l [fa] : 0 ” 。

    两道题用同样的代码即可。

    #include<cstdio>
    #include<cstring>
    #include<string>//
    #include<algorithm>
    #define ll long long
    using namespace std;
    int Mx(int a,int b){return a>b?a:b;}
    const int N=1e5+5,M=N<<1,K=27;//<<1
    int n,k,go[M][K],l[M],fa[M],tot=1;
    int tx[M],q[M],ans[M],ct[M],vis[M];
    int cz(int p,int w)
    {
      int q=go[p][w],nq=++tot;l[nq]=l[p]+1;
      fa[nq]=fa[q];fa[q]=nq;
      memcpy(go[nq],go[q],sizeof go[q]);
      for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
      return nq;
    }
    int ins(int p,int w)
    {
      if(go[p][w])
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)return go[p][w];
          else return cz(p,w);//////
        }
      else
        {
          int np=++tot;l[np]=l[p]+1;
          for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
          if(!p)fa[np]=1;
          else
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)fa[np]=q;
          else fa[np]=cz(p,w);
        }
          return np;
        }
    }
    void Rsort(int mxn)
    {
      for(int i=1;i<=tot;i++)tx[l[i]]++;
      for(int i=1;i<=mxn;i++)tx[i]+=tx[i-1];
      //  for(int i=tot;i;i--)q[tx[l[i]]--]=i;
      for(int i=1;i<=tot;i++)q[tx[l[i]]--]=i;
    }
    string ch[N]; int len[N];
    int main()
    {
      scanf("%d%d",&n,&k); char tp[N]; int mxn=0;
      for(int i=1,d;i<=n;i++)
        {
          scanf("%s",tp);len[i]=strlen(tp);mxn=Mx(mxn,len[i]);
          ch[i]=tp;
        }
      for(int i=1;i<=n;i++)
        for(int lm=len[i],pr=1,j=0;j<lm;j++)
          pr=ins(pr,ch[i][j]-'a'+1);
      for(int i=1;i<=n;i++)
        for(int lm=len[i],cr=1,j=0;j<lm;j++)
          {
        cr=go[cr][ch[i][j]-'a'+1];
        for(int p=cr;p&&vis[p]!=i;p=fa[p])
          ct[p]++,vis[p]=i;
          }
      Rsort(mxn);
      for(int i=2,d;i<=tot;i++)
        {d=q[i];ans[d]=ans[fa[d]]+(ct[d]>=k?l[d]-l[fa[d]]:0);}//
      for(int i=1;i<=n;i++)
        {
          ll prn=0;
          for(int lm=len[i],cr=1,j=0;j<lm;j++)
        {
          cr=go[cr][ch[i][j]-'a'+1];
          prn+=ans[cr];
        }
          printf("%lld ",prn);
        }
      puts("");return 0;
    }
    View Code

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2780

    和上一道题一样。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    using namespace std;
    int const xn=2e5+5;
    const int N=1e4+5,M=2e5+5,N2=4e5+5,K=27;
    int n,go[M][K],fa[M],l[M],ct[M],tot=1;
    string s[N];int len[N],vis[M];
    int cz(int p,int w)
    {
      int q=go[p][w],nq=++tot; l[nq]=l[p]+1;/////////l[p]+1 not l[q]+1!!!!!
      fa[nq]=fa[q];fa[q]=nq;
      memcpy(go[nq],go[q],sizeof go[q]);
      for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
      return nq;
    }
    int ins(int p,int w)
    {
      if(go[p][w])
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)return q; else return cz(p,w);
        }
      else
        {
          int np=++tot;l[np]=l[p]+1;
          for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
          if(!p)fa[np]=1;
          else
        {
          int q=go[p][w];
          if(l[q]==l[p]+1)fa[np]=q; else fa[np]=cz(p,w);
        }
          return np;
        }
    }
    char ch[N2]; int Q;
    int main()
    {
      scanf("%d%d",&n,&Q);
      for(int i=1;i<=n;i++)
        {
          scanf("%s",ch);len[i]=strlen(ch);
          s[i]=(string)ch;
          for(int pr=1,j=0,lm=len[i];j<lm;j++)
        pr=ins(pr,ch[j]-'a'+1);
        }
      for(int i=1;i<=n;i++)
        for(int cr=1,j=0,lm=len[i];j<lm;j++)
          {
        cr=go[cr][s[i][j]-'a'+1];
        for(int p=cr;p>1&&vis[p]!=i;p=fa[p])
          ct[p]++,vis[p]=i;
          }
      while(Q--)
        {
          scanf("%s",ch);int lm=strlen(ch),cr=1;
          for(int j=0;j<lm&&cr;j++)
        cr=go[cr][ch[j]-'a'+1];
          printf("%d
    ",ct[cr]);
        }
      return 0;
    }
    View Code
  • 相关阅读:
    BigDecimal 类型数据比较大小
    list排序,顺序,倒序
    springboot添加log4j日志配置log4j.xml生成日志文件
    mybatis使用@param("xxx")注解传参和不使用的区别
    jetty 插件启动指定端口号
    javaweb项目静态资源被拦截的解决方法
    day15 Python全局变量和局部变量
    阿里云操作视频
    Python基础视频
    马哥Python视频
  • 原文地址:https://www.cnblogs.com/Narh/p/10290569.html
Copyright © 2011-2022 走看看