【SPOJ DISUBSTR】Distinct Substrings 后缀数组

来源:互联网 发布:access数据库编辑器 编辑:程序博客网 时间:2024/06/05 14:17

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:

2CCCCCABABA

Sample Output:

59

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.


SPOJ还有一个题是【SUBST1 - New Distinct Substrings】,一模一样,不过nlog^2n过不了。

计数问题,贡献是当前后缀生成的子串数目减去高度数组的大小,也就是重复的子串数目。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const int SZ = 1000010;int lcp[SZ],sa[SZ],tmp[SZ],k = 1,n,rank[SZ];bool cmp_sa(int i,int j){    if(rank[i] != rank[j]) return rank[i] < rank[j];    else    {        int x = i + k <= n ? rank[i + k] : -1;        int y = j + k <= n ? rank[j + k] : -1;        return x < y;    }}void get_sa(char s[]){    for(int i = 0;i <= n;i ++)    {        sa[i] = i;        rank[i] = i == n ? -1 : s[i];    }    for(k = 1;k <= n;k <<= 1)    {        sort(sa,sa + 1 + n,cmp_sa);        tmp[sa[0]] = 0;        for(int i = 1;i <= n;i ++)            tmp[sa[i]] = tmp[sa[i - 1]] + (cmp_sa(sa[i - 1],sa[i]) ? 1 : 0);        for(int i = 0;i <= n;i ++)            rank[i] = tmp[i];    }}void get_lcp(char s[]){    int h = 0;    lcp[0] = 0;    for(int i = 0;i <= n;i ++)        rank[sa[i]] = i;    for(int i = 0;i < n;i ++)    {        int j = sa[rank[i] - 1];    //  cout<<"sa:"<<i<<" "<<j<<endl;        if(h) h --;        while(i + h < n && j + h < n)        {            if(s[i + h] == s[j + h]) h ++;            else break;        }        lcp[rank[i] - 1] = h;    }}LL ask(){    LL ans = 0;    for(int i = 1;i <= n;i ++)    {        ans += n - sa[i] - lcp[i];//      cout<<n - sa[i] - lcp[i]<<endl;    }    return ans;}void init(){    memset(sa,0,sizeof(sa));    memset(lcp,0,sizeof(lcp));    memset(rank,0,sizeof(rank));    memset(tmp,0,sizeof(tmp));}char s[SZ];int main(){    int T;    scanf("%d",&T);    while(T --)    {        init();        scanf("%s",s);        n = strlen(s);        get_sa(s);        get_lcp(s);    /*  for(int i = 0;i <= n;i ++)            printf("%d ",lcp[i]); puts("");        for(int i = 0;i <= n;i ++)            printf("%d ",sa[i]); puts("");*/        printf("%lld\n",ask());    }    return 0;}/*2CCCCCABABA*/
0 0
原创粉丝点击