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
  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/Narh/p/10290569.html
Copyright © 2011-2022 走看看