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;	
    }
    
  • 相关阅读:
    Python print "hello world" SyntaxError: invalid syntax
    Parencodings(模拟)
    Do the Untwist(模拟)
    Jugs(回溯法)
    Anagrams by Stack(深度优先搜索)
    Fire Net(深度优先搜索)
    Integer Numbers
    Codeforces Beta Round #34 (Div. 2) E. Collisions
    什么是Qt Widget?
    codeblocks快捷键(转)
  • 原文地址:https://www.cnblogs.com/duzhiyuan/p/11938267.html
Copyright © 2011-2022 走看看