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

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

洛谷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;
}
全部评论

相关推荐

今天 11:16
湖南大学 Web前端
我看到好多人都在说0offer好焦虑,结果一看是投了百度快手字节啥的。好像大家都是只想通过校招进大厂,对小公司是不考虑的吗😂可是能进大厂的难道不是只有少部分人吗,真心发问
梦想是成为七海千秋:沉默的大多数吧,喜欢晒的都是能引起共鸣的大厂,找小厂的人,别人也不认识你这个小厂,就自己偷偷找了实际上大多数人哪有什么机会能找到大厂
点赞 评论 收藏
分享
06-02 15:17
门头沟学院 Java
心爱的idea:怎么会呢 应该是打招呼有问题 问就说实习6个月全国可飞随时到岗
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务