spoj694 DISUBSTR - Distinct Substrings

DISUBSTR - Distinct Substrings

Description

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.

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.

题目大意

给定一个字符串,求不相同的子串的个数。

题解

论文中例5,比较简单的一道模板题。
考虑每个子串对应一个后缀的前缀,题目就是求所有后缀不相同的前缀的个数。按照sa的顺序计算每个后缀,那么第sa[i]个后缀对答案的贡献就是 nsa[i]+1height[i]

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

const int N = 1000 + 10;
char s[N];
int t, n, a[N];
int v[N], sa[2][N], rk[2][N], ht[N], p, q, k, ans;

void init(){
    scanf("%s", s+1);
    n = strlen(s+1);
    for(int i = 1; i <= n; i++) a[i] = (int) s[i];
    memset(sa, 0, sizeof(sa));
    memset(rk, 0, sizeof(rk));
    memset(ht, 0, sizeof(ht));
    memset(v, 0, sizeof(v));
    ans = 0;
}
void calsa(int *sa1, int *rk1, int *sa2, int *rk2){
    for(int i = 1; i <= n; i++) v[rk1[sa1[i]]] = i;
    for(int i = n; i >= 1; i--) if(sa1[i] > k) sa2[v[rk1[sa1[i]-k]]--] = sa1[i] - k;
    for(int i = n-k+1; i <= n; i++) sa2[v[rk1[i]]--] = i;
    for(int i = 1; i <= n; i++)
        rk2[sa2[i]] = rk2[sa2[i-1]] + (rk1[sa2[i-1]] != rk1[sa2[i]] || rk1[sa2[i-1]+k] != rk1[sa2[i]+k]);
}
void calheight(){
    int k = 0;
    for(int i = 1; i <= n; i++){
        if(k) k--;
        int j = sa[p][rk[p][i]-1];
        while(a[i+k] == a[j+k]) k++;
        ht[rk[p][i]] = k;
    }
}
void work(){
    scanf("%d", &t);
    while(t--){
        init();
        p = 0, q = 1;
        for(int i = 1; i <= n; i++) v[a[i]]++;
        for(int i = 1; i <= 128; i++) v[i] += v[i-1];
        for(int i = 1; i <= n; i++) sa[p][v[a[i]]--] = i;
        for(int i = 1; i <= n; i++)
            rk[p][sa[p][i]] = rk[p][sa[p][i-1]] + (a[sa[p][i]] != a[sa[p][i-1]]);
        memset(v, 0, sizeof(v));
        k = 1;
        while(k < n){
            calsa(sa[p], rk[p], sa[q], rk[q]);
            p ^= 1, q ^= 1, k <<= 1;
        }
        calheight();
        for(int i = 1; i <= n; i++)
            ans += n - sa[p][i] + 1 - ht[i];
        printf("%d\n", ans);
    }
}

int main(){
    work();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值