zoukankan      html  css  js  c++  java
  • SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )

    题意 : 对于给出的串,输出其不同长度的子串的种类数

    分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀中找出不同的并计数呢?思路就是所有的可能子串数 - 重复的子串数。首先我们容易得到一个长度为 len 的串的子串数为 len * ( len + 1) / 2。那如何知道重复的子串数呢?答案就是利用后缀数组去跑一遍 Height ,得到所有的最长公共前缀(LCP),这些最长公共前缀的值都存在了 Height 中,对于任意两个后缀的最长公共前缀长度实际就是重复出现的子串数,那么只要遍历一遍 Height 数组,用刚刚得出来的总子串数减去所有的 Height 值即可

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 50010;
    int sa[maxn],s[maxn],wa[maxn], wb[maxn], Ws[maxn], wv[maxn];
    int Rank[maxn], height[maxn];
    bool cmp(int r[], int a, int b, int l){ return r[a] == r[b] && r[a+l] == r[b+l]; }
    void da(int r[], int sa[], int n, int m)
    {
        int i, j, p, *x = wa, *y = wb;
        for (i = 0; i < m; ++i) Ws[i] = 0;
        for (i = 0; i < n; ++i) Ws[x[i]=r[i]]++;
        for (i = 1; i < m; ++i) Ws[i] += Ws[i-1];
        for (i = n-1; i >= 0; --i) sa[--Ws[x[i]]] = i;
        for (j = 1, p = 1; p < n; j *= 2, m = p)
        {
            for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
            for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
            for (i = 0; i < n; ++i) wv[i] = x[y[i]];
            for (i = 0; i < m; ++i) Ws[i] = 0;
            for (i = 0; i < n; ++i) Ws[wv[i]]++;
            for (i = 1; i < m; ++i) Ws[i] += Ws[i-1];
            for (i = n-1; i >= 0; --i) sa[--Ws[wv[i]]] = y[i];
            for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
                x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
        }
    }
    void calheight(int r[], int sa[], int n)
    {
        int i, j, k = 0;
        for (i = 1; i <= n; ++i) Rank[sa[i]] = i;
        for (i = 0; i < n; height[Rank[i++]] = k)
            for (k?k--:0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k++);
    }
    
    char SS[maxn];
    int S[maxn];
    int main(void)
    {
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            scanf("%s", SS);
            int len = strlen(SS);
            for(int i=0; i<len; i++) S[i] = (int)SS[i];
            S[len] = 0;
    
            da(S, sa, len+1, 128);
            calheight(S, sa, len);
    
            long long tmp = len;
            long long ans = (tmp * (tmp+1)) / 2;
            for(int i=2; i<=len; i++) ans -= height[i];//or ans += len - i - height[Rank[i]];
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    超级管理员登录后如果连续XX分钟没有操作再次操作需要重新登录
    linux下连接本地的navicate
    linux 日常中会用到的命令(持续更新)
    关于PHP的 PHP-FPM进程CPU 100%的一些原因分析和解决方案
    VMware Workstation 14 激活码
    破解phpstorm
    redis五种数据类型的使用场景
    关于Nginx负载均衡的6种策略
    PHP和PHP-FPM 配置文件优化
    redis配置文件详解
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7868700.html
Copyright © 2011-2022 走看看