• [TyvjP1515] 子串统计 [luoguP2408] 不同子串个数(后缀数组)


    Tyvj传送门

    luogu传送门

    经典题

    统计一个字符串中不同子串的个数

    一个字符串中的所有子串就是所有后缀的前缀

    先求出后缀数组,求出后缀数组中相邻两后缀的 lcp

    那么按照后缀数组中的顺序遍历求解

    每一个后缀 suffix(sa[i]) 对于答案的贡献为 len - sa[i] - height[i]

    len - sa[i] 为当前后缀的长度,也就是当前后缀所有前缀的个数(字符串从 0 开始)

    height[i] 就是相邻两后缀 lcp,因为有可能会有相同前缀,而相同前缀在前面已经计算过了

    为什么只需要 height 数组,而不用把任意两后缀的 lcp 求出来呢?

    因为所有后缀已经按照字典序排序了,也就是说,sa[i] 和 sa[i - 1] 的 lcp 即为 sa[i] 和 sa[0 ~ i - 1] 的所有 lcp 的最大值。

    ——代码(Tyvj)

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #define N 200001
     5 #define LL long long
     6 
     7 LL ans;
     8 int len, m = 256;
     9 int buc[N], x[N], y[N], sa[N], rank[N], height[N];
    10 char s[N];
    11 
    12 inline void build_sa()
    13 {
    14     int i, k, p;
    15     for(i = 0; i < m; i++) buc[i] = 0;
    16     for(i = 0; i < len; i++) buc[x[i] = s[i]]++;
    17     for(i = 1; i < m; i++) buc[i] += buc[i - 1];
    18     for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i;
    19     for(k = 1; k <= len; k <<= 1)
    20     {
    21         p = 0;
    22         for(i = len - 1; i >= len - k; i--) y[p++] = i;
    23         for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
    24         for(i = 0; i < m; i++) buc[i] = 0;
    25         for(i = 0; i < len; i++) buc[x[y[i]]]++;
    26         for(i = 1; i < m; i++) buc[i] += buc[i - 1];
    27         for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i];
    28         std::swap(x, y);
    29         p = 1, x[sa[0]] = 0;
    30         for(i = 1; i < len; i++)
    31             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
    32         if(p >= len) break;
    33         m = p;
    34     }
    35 }
    36 
    37 inline void build_height()
    38 {
    39     int i, j, k = 0;
    40     for(i = 0; i < len; i++) rank[sa[i]] = i;
    41     for(i = 0; i < len; i++)
    42     {
    43         if(!rank[i]) continue;
    44         if(k) k--;
    45         j = sa[rank[i] - 1];
    46         while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++;
    47         height[rank[i]] = k;
    48     }
    49 }
    50 
    51 int main()
    52 {
    53     int i;
    54     scanf("%d", &len);
    55     getchar();
    56     for(i = 0; i < len; i++)
    57     {
    58         s[i] = getchar();
    59         if((i + 1) % 80 == 0) getchar();
    60     }
    61     build_sa();
    62     build_height();
    63     for(i = 0; i < len; i++) ans += (LL)(len - sa[i] - height[i]);
    64     printf("%lld
    ", ans);
    65     return 0;
    66 }
    View Code

    洛谷那题好像数据有点问题。

  • 相关阅读:
    tensorflow 学习笔记 多层感知机
    tensorflow 学习笔记(转)
    python学习笔记 map&&reduce
    java中的接口和php的接口的区别
    php中的内存划分
    workerman stop失败
    Java中的内存划分
    php和java语法区别
    Docker:Swarm + Stack 一站式部署容器集群
    docker 配置私有仓库
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6991184.html
Copyright © 2020-2023  润新知