zoukankan      html  css  js  c++  java
  • 后缀自动机

    特征

    1、对于每个节点,父节点的接受串是该节点的接受串的后缀,而且是最长的那个。用该节点的len减去父节点的fa.len,就是该节点表示的串中父节点不能表示的串个数。

    同理,当插入这个节点,出现的新不同子串个数就是len-fa.len。

    2、每个节点表示串出现的次数,是这个节点子树上有效节点的总数。(有效节点指插入该字符产生的那个节点,也就是代码中extend中的clone节点)。

    这样我们初始化有效节点为1,然后拓扑排序dp,就可以O(n)得到每个节点出现次数。

    3、后缀自动机是一张有向无环图,其中顶点是状态,而边代表了状态之间的转移。

    4、任意路径“匹配”某一子串,该子串由路径中边的标记组成。

    5、如果程序中所处理字符串的最大可能长度是MAXN,那么至多会占用2*MAXN-1个状态。

    6、由长度为n的字符串s建立的后缀自动机中,转移的数量不超过3n-4(对于n>=3)。

    模板

      1 #include<iostream>
      2 #include<cstring>
      3 using namespace std;
      4 const int maxn = 1e5 + 10;
      5 struct node
      6 {
      7     int ch[26], par,len;
      8 }SA[maxn*2];
      9 int sz, root, last;
     10 void init()
     11 {
     12     sz = root = last = 0;
     13     SA[0].len = 0;
     14     SA[0].par = -1;
     15     memset(SA[0].ch, 0, sizeof(SA[0].ch));
     16 }
     17 
     18 void extend(int c)
     19 {//向当前字符串的尾部添加一个字符
     20     int p = last, cur = ++sz;
     21     SA[cur].len = SA[p].len + 1;
     22     for (; p!=-1 && !SA[p].ch[c]; p = SA[p].par) SA[p].ch[c] = cur;
     23     if (p == -1) SA[cur].par = root;
     24     else
     25     {
     26         int q = SA[p].ch[c];
     27         if (SA[q].len == SA[p].len + 1) SA[cur].par = q;
     28         else
     29         {
     30             int clone = ++sz;
     31             SA[clone] = SA[q];
     32             SA[clone].len = SA[p].len + 1;
     33             SA[q].par = SA[cur].par = clone;
     34             for (; p != -1 && SA[p].ch[c] == q; p = SA[p].par) SA[p].ch[c] = clone;
     35         }
     36     }
     37     last = cur;
     38 }
     39 int encode(char c)
     40 {
     41     return c - 'a';
     42 }
     43 int Count_substrings()
     44 {//不同子串的个数
     45     int ans = 0;
     46     for (int i = 1; i <= sz; i++)
     47     {
     48         ans += SA[i].len - SA[SA[i].par].len;
     49     }
     50     return ans;
     51 }
     52 bool find_substring(int*des, int n)
     53 {//寻找子串是否存在
     54     int i=0, cur = SA[root].ch[des[0]];
     55     while (i < n&&cur)
     56     {
     57         i++;
     58         cur = SA[cur].ch[des[i]];
     59     }
     60     if (i == n) return true;
     61     else return false;
     62 }
     63 int r[maxn<<2],w[maxn];
     64 void RadixSort(int n)
     65 {//拓扑排序
     66     for(int i=0;i<=n;i++) w[i]=0; 
     67     for(int i=1;i<=sz;i++) w[SA[i].len]++;
     68     for(int i=1;i<=n;i++) w[i]+=w[i-1];
     69     for(int i=sz;i>=1;i--) r[w[SA[i].len]--]=i;
     70     r[0]=0;
     71 }
     72 int LCS(int*P,int lenP)
     73 {//求串P与建立后缀自动机的串的最长公共子串
     74     int lcs=0,now=0,ans=0;
     75     for(int i=0;i<lenP;i++)
     76     {
     77         if(SA[now].ch[P[i]])
     78         {
     79             now=SA[now].ch[P[i]];
     80             lcs++;
     81         }
     82         else
     83         {
     84             while(now!=0&&SA[now].ch[P[i]]==0) now=SA[now].par;
     85             if(now==0) now=root,lcs=0;
     86             else lcs=SA[now].len+1,now=SA[now].ch[P[i]];
     87         }
     88         ans=max(ans,lcs);
     89     }
     90     return ans;
     91 }
     92 long long cal_k_strings()
     93 {//寻找原串中出现次数为k的子串数目
     94     
     95     return 0;
     96 }
     97 char s[maxn],ss[maxn];
     98 int tmp[maxn];
     99 int main()
    100 {
    101     scanf("%s", s);
    102     printf("%s
    ",s);
    103     int len = strlen(s);
    104     init();
    105     for (int i = 0; i < len; i++) extend(encode(s[i]));//对于多串,每次将last=root再插入新串
    106     printf("不同的子串个数:%d
    ", Count_substrings());
    107     RadixSort(len);
    108     printf("sz:%d
    ",sz);
    109     for(int i=0;i<=sz;i++) printf("%d ",r[i]);
    110     printf("
    ");
    111     scanf("%s", ss);
    112     len = strlen(ss);
    113     for (int i = 0; i < len; i++) tmp[i] = encode(ss[i]);
    114     if (find_substring(tmp, len)) printf("yes
    ");
    115     else printf("no
    ");
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    模拟按键'ESC',解决韩语等输入法对输入框(codemirror)的支持
    grpc的基础知识
    HttpClientFactory 是 HttpClient 的正确使用方式
    Workflow Core + asp.net core 5.0 实现简单审批工作流
    GitHub自动化部署(CD) asp.net core 5.0 项目(免费空间)
    CleanArchitecture Application代码生成插件-让程序员告别CURD Ctrl+C Ctrl+V
    C# 字符串转成JSON对象 反射获取属性值
    java设计模式-状态模式
    2021目前可用的百度网盘不限速下载方法
    docker映射配置文件
  • 原文地址:https://www.cnblogs.com/ivan-count/p/9485922.html
Copyright © 2011-2022 走看看