• bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机


    题目: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 树一样处理了重复节点;

    基数排序后DP,f 数组求的直接是这个点及其祖先的答案;

    开 2e5 就可以,因为每次加入一个字符最多新增2个点。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=2e5+5;
    int n,K,cnt=1,go[xn][30],len[xn],fa[xn],vis[xn],tot[xn],lst;
    ll f[xn]; 
    string s[xn];
    int work(int p,int w)
    {
      int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1;
      memcpy(go[nq],go[q],sizeof go[q]);
      fa[nq]=fa[q]; fa[q]=nq;
      for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
      return nq;
    }
    int ext(int p,int w)
    {
      if(go[p][w])
        {
          int q=go[p][w]; 
          if(len[q]==len[p]+1)return q; return work(p,w);
        }
      int np=++cnt; len[np]=len[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(len[q]==len[p]+1)fa[np]=q;
          else fa[np]=work(p,w);
        }
      return np;
    }
    int tax[xn],q[xn],l[xn];
    void rsort()
    {
      for(int i=1;i<=cnt;i++)tax[len[i]]++;
      for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1];
      for(int i=cnt;i;i--)q[tax[len[i]]--]=i;
    }
    char dc[xn];
    int main()
    {
      scanf("%d%d",&n,&K);
      for(int i=1;i<=n;i++)
        {
          scanf("%s",dc); s[i]=string(dc); l[i]=strlen(dc); lst=1;
          for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a');
        }
      for(int i=1;i<=n;i++)
        {
          int nw=1;
          for(int j=0;j<l[i];j++)
        {
          nw=go[nw][s[i][j]-'a'];
          for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++;
        }
        }
      rsort();
      for(int i=1,x;i<=cnt;i++)
        f[x=q[i]]=f[fa[x]]+(tot[x]>=K?len[x]-len[fa[x]]:0);//
      for(int i=1;i<=n;i++)
        {
          ll ans=0; int nw=1;
          for(int j=0;j<l[i];j++)
        nw=go[nw][s[i][j]-'a'],ans+=f[nw];
          printf("%lld ",ans);
        }
      puts(""); return 0;
    }
    View Code

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

    几乎完全一样,但忘记写 lst=1 呆了半小时...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=2e5+5;
    int n,m,cnt=1,fa[xn],l[xn],go[xn][30],len[xn],tot[xn],vis[xn],lst;
    char dc[xn]; string s[xn];
    int work(int p,int w)
    {
      int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1;
      memcpy(go[nq],go[q],sizeof go[q]);
      fa[nq]=fa[q]; fa[q]=nq;
      for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
      return nq;
    }
    int ext(int p,int w)
    {
      if(go[p][w])
        {
          int q=go[p][w];
          if(len[q]==len[p]+1)return q; return work(p,w);
        }
      int np=++cnt; len[np]=len[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(len[q]==len[p]+1)fa[np]=q;
          else fa[np]=work(p,w);
        }
      return np;
    }
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
        {
          scanf("%s",dc); l[i]=strlen(dc); s[i]=string(dc); lst=1;//lst=1!!
          for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a');
        }
      for(int i=1;i<=n;i++)
        {
          int nw=1;
          for(int j=0;j<l[i];j++)
        {
          nw=go[nw][s[i][j]-'a'];
          for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++;
        }
        }
      for(int i=1;i<=m;i++)
        {
          scanf("%s",dc); int lth=strlen(dc),nw=1;
          for(int j=0;j<lth;j++)nw=go[nw][dc[j]-'a'];
          printf("%d
    ",tot[nw]);
        }
      return 0;
    }
    View Code
  • 相关阅读:
    maven笔记
    enum笔记
    mysql笔记
    git笔记
    spark笔记
    使用GitHub进行团队合作
    深度学习网站
    顶级论文索引网站
    研究生-数学建模集
    算法练习网站
  • 原文地址:https://www.cnblogs.com/Zinn/p/10290480.html
Copyright © 2020-2023  润新知