• 后缀数组求不同子串的个数


    后缀数组求不同子串的个数

    洛谷P2408

    如果学会后缀数组,那么这题就是一个对于后缀数组的结果的应用,具体看solve函数的注释

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    const int N = 1e6 + 10;
    const int INF = 0x3f3f3f3f;
    
    struct SuffixArray {
    
        ///记住数组从1开始
        /// SA后缀数组, rak排名, height
    
        static const int MAXN = 1e6 + 10;
    
        int N, M, rak[MAXN], sa[MAXN], tax[MAXN], tp[MAXN], Height[MAXN];
    
        char s[MAXN];
    
        void Qsort() {
            for(int i = 0; i <= M; i++) tax[i] = 0;
            for(int i = 1; i <= N; i++) tax[rak[i]]++;
            for(int i = 1; i <= M; i++) tax[i] += tax[i - 1];
            for(int i = N; i >= 1; i--) sa[ tax[rak[tp[i]]]-- ] = tp[i];
        }
    
        void SuffixSort() {
            M = 300;
            if(N == 0) N = strlen(s + 1);
            for(int i = 1; i <= N; i++) rak[i] = s[i], tp[i] = i;
            Qsort();
            for(int w = 1, p = 0; p < N; M = p, w <<= 1) {
                p = 0;
                for(int i = 1; i <= w; i++) tp[++p] = N - w + i;
                for(int i = 1; i <= N; i++) if(sa[i] > w) tp[++p] = sa[i] - w;
                Qsort();
                std::swap(tp, rak);
                rak[sa[1]] = p = 1;
                for(int i = 2; i <= N; i++)
                    rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
            }
        }
    
        void GetHeight() {
            int j, k = 0;
            for(int i = 1; i <= N; i++) {
                if(k) k--;
                int j = sa[rak[i] - 1];
                while(s[i + k] == s[j + k]) k++;
                Height[rak[i]] = k;
            }
        }
    
        void debug() {
            printf("id    :");
            for (int i = 1; i <= N; i++ ) printf("%-3d ", i); puts("");
            printf("rank  :");
            for (int i = 1; i <= N; i++ ) printf("%-3d ", rak[i]); puts("");
            printf("sa    :");
            for (int i = 1; i <= N; i++ ) printf("%-3d ", sa[i]); puts("");
            printf("height:");
            for (int i = 1; i <= N; i++ ) printf("%-3d ", Height[i]); puts("");
        }
    
        void solve() {
            /**
            给你一个长为N的字符串,求不同的子串的个数?
            对于一个后缀sa[i],它产生了n-sa[i]个前缀,减去height[i]个相同的前缀(与前一个比较),
            则产生了n-sa[i]-height[i]个子串。累加后即结果。
            */
            long long ans = 0;
            for(int i = 1; i <= N; i++ ) {
                ans += N + 1 - sa[i] - Height[i];
            }
            cout << ans << endl;
        }
    
    } cwl;
    
    int main() {
        while(~scanf("%d", &cwl.N) && cwl.N) {
            scanf("%s", cwl.s + 1);
            cwl.SuffixSort();
            cwl.GetHeight();
    //        cwl.debug();
            cwl.solve();
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    阿里中间件——消息中间件Notify和MetaQ
    大型网站架构系列:分布式消息队列
    Mycat
    spring集成mybatis实现mysql读写分离
    mysql5.7.18的安装与主从复制
    NuGet学习笔记(3) 搭建属于自己的NuGet服务器
    NuGet学习笔记(1)——初识NuGet及快速安装使用
    Android 中使用 html 作布局文件
    获取WebView加载HTML时网页中的内容
    android学习——popupWindow 在指定位置上的显示
  • 原文地址:https://www.cnblogs.com/Q1143316492/p/9446920.html
Copyright © 2020-2023  润新知