zoukankan      html  css  js  c++  java
  • SPOJ

    Given a string, we need to find the total number of its distinct substrings.

    Input

    T- number of test cases. T<=20;
    Each test case consists of one string, whose length is <= 1000

    Output

    For each test case output one number saying the number of distinct substrings.

    Example

    Sample Input:
    2
    CCCCC
    ABABA

    Sample Output:
    5
    9

    Explanation for the testcase with string ABABA: 
    len=1 : A,B
    len=2 : AB,BA
    len=3 : ABA,BAB
    len=4 : ABAB,BABA
    len=5 : ABABA
    Thus, total number of distinct substrings is 9.

    题意:

    为字符串的子串个数

    思路:

    使用后缀数组解决。

    按sa遍历后缀数组,每一个后缀的贡献即为n-sa[i]-lcp[i];

    这里的lcp就是你们所说的height

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<ctime>
    
    #define fuck(x) cout<<#x<<" = "<<x<<endl;
    #define debug(a, x) cout<<#a<<"["<<x<<"] = "<<a[x]<<endl;
    #define ls (t<<1)
    #define rs ((t<<1)|1)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 100086;
    const int maxm = 100086;
    const int inf = 0x3f3f3f3f;
    const ll Inf = 999999999999999999;
    const int mod = 1000000007;
    const double eps = 1e-6;
    const double pi = acos(-1);
    
    char s[maxn];
    int len,Rank[maxn],sa[maxn],k,tmp[maxn];
    bool compare_sa(int i, int j) {
        if (Rank[i] != Rank[j]) { return Rank[i] < Rank[j]; }
        //如果以i开始,长度为k的字符串的长度,已经超出了字符串尾,那么就赋值为-1
        //这是因为,在前面所有数据相同的情况下,字符串短的字典序小.
        int ri = i + k <= len ? Rank[i + k] : -inf;
        int rj = j + k <= len ? Rank[j + k] : -inf;
        return ri < rj;
    }
    
    void construct_sa() {
        //初始的RANK为字符的ASCII码
        for (int i = 0; i <= len; i++) {
            sa[i] = i;
            Rank[i] = i < len ? s[i] : -inf;
        }
        for (k = 1; k <= len; k *= 2) {
            sort(sa, sa + len + 1, compare_sa);
            tmp[sa[0]] = 0;
            //全新版本的RANK,tmp用来计算新的rank
            //将字典序最小的后缀rank计为0
            //sa之中表示的后缀都是有序的,所以将下一个后缀与前一个后缀比较,如果大于前一个后缀,rank就比前一个加一.
            //否则就和前一个相等.
            for (int i = 1; i <= len; i++) {
                tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= len; i++) {
                Rank[i] = tmp[i];
    
            }
        }
    }
    int lcp[maxn];
    
    
    void construct_lcp(){
    //    for(int i=0;i<=n;i++){Rank[sa[i]]=i;}
    
        int h=0;
        lcp[0]=0;
        for(int i=0;i<len;i++){//i为后缀数组起始位置
            int j = sa[Rank[i]-1];//获取当前后缀的前一个后缀(排序后)
            if(h>0)h--;
            for(;j+h<len&&i+h<len;h++){
                if(s[j+h]!=s[i+h])break;
            }
            lcp[Rank[i]]=h;
        }
    }
    
    
    int main() {
        int T;
        scanf("%d",&T);
        while (T--){
            scanf("%s",s);
            len = strlen(s);
            construct_sa();
            construct_lcp();
    
            int ans=0;
            for(int i=1;i<=len;i++){
                ans+=(len-sa[i]-lcp[i]);
            }
            printf("%d
    ",ans);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    hihocoder #1407 : 后缀数组二·重复旋律2
    后缀数组基本问题QAQ
    hihocoder #1403 : 后缀数组一·重复旋律
    20170116小测233
    HDU 4779:Tower Defense
    BZOJ 2563: 阿狸和桃子的游戏
    Codeforces 460D. Little Victor and Set
    Codeforces 297C. Splitting the Uniqueness
    BZOJ 2565: 最长双回文串
    Manacher--雾窗寒对遥天暮,暮天遥对寒窗雾
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/11174040.html
Copyright © 2011-2022 走看看