zoukankan      html  css  js  c++  java
  • 【后缀数组】【LuoguP2408】 不同子串个数

    题目链接

    题目描述

    给你一个长为N的字符串,求不同的子串的个数

    我们定义两个子串不同,当且仅当有这两个子串长度不一样 或者长度一样且有任意一位不一样。

    子串的定义:原字符串中连续的一段字符组成的字符串

    说明

    对于100%的数据,N≤10^5

    思路

    能发现任何一个子串都是某一个后缀的前缀

    实际上就是求所有后缀有多少本质不同的前缀

    我们考虑按照将所有后缀按照字典序排序,那么每次新加进来的一个后缀的前缀的个数为 (n-sa[i]+1),但是与前面重复的前缀有 (H[i])

    因为对于 (sa[i]),它与前面的所有后缀的最长公共前缀就是它与 (sa[i-1]) 的最长公共前缀,所以重复的前缀有 (H[i])

    我们把后缀 (sa[i ]) 和后缀 (sa[i - 1]) 公共前缀看成是 (i-1) 所独有的子串,那么答案就是 (sum_{i}n-sa[i]+1-H[i])

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 1000010
    #define ll long long
    using namespace std;
    
    int n;
    char s[maxn];
    
    int tax[maxn], tp[maxn], sa[maxn], rk[maxn], M = 122;
    void rsort() {
        for (int i = 0; i <= M; ++i) tax[i] = 0;
        for (int i = 1; i <= n; ++i) ++tax[rk[i]];
        for (int i = 1; i <= M; ++i) tax[i] += tax[i - 1];
        for (int i = n; i; --i) sa[tax[rk[tp[i]]]--] = tp[i];
    }
    
    int c1, H[maxn];
    void SA() {
        for (int i = 1; i <= n; ++i) rk[i] = s[i], tp[i] = i;
        rsort();
        for (int k = 1; k < n; k *= 2) {
            if (c1 == n) break; M = c1; c1 = 0; 
            for (int i = n - k + 1; i <= n; ++i) tp[++c1] = i;
            for (int i = 1; i <= n; ++i) if (sa[i] > k) tp[++c1] = sa[i] - k;
            rsort(); swap(tp, rk); rk[sa[1]] = c1 = 1; 
            for (int i = 2; i <= n; ++i) {
                if (tp[sa[i - 1]] != tp[sa[i]] || tp[sa[i - 1] + k] != tp[sa[i] + k]) ++c1; 
                rk[sa[i]] = c1;
            }
        }
        int lcp = 0;
        for (int i = 1; i <= n; ++i) {
            if (lcp) --lcp;
            int j = sa[rk[i] - 1];
            while (s[j + lcp] == s[i + lcp]) ++lcp;
            H[rk[i]] = lcp; 
        }
    }
    
    ll ans; 
    int main() {
        scanf("%d%s", &n, s + 1); SA();
        for (int i = 1; i <= n; ++i) ans += n - sa[i] + 1 - H[i];
        cout << ans << endl; 
        return 0;	
    }
    
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/duzhiyuan/p/11938267.html
Copyright © 2011-2022 走看看