zoukankan      html  css  js  c++  java
  • [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

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

  • 相关阅读:
    169. Majority Element
    283. Move Zeroes
    1331. Rank Transform of an Array
    566. Reshape the Matrix
    985. Sum of Even Numbers After Queries
    1185. Day of the Week
    867. Transpose Matrix
    1217. Play with Chips
    766. Toeplitz Matrix
    1413. Minimum Value to Get Positive Step by Step Sum
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6991184.html
Copyright © 2011-2022 走看看