首页 > 代码库 > Distinct Substrings(spoj 694)

Distinct Substrings(spoj 694)

题意:要求不同子串的个数

/*
    先求出height数组,不难看出height之和就是重复的字符串个数,用总的减去它就行了。 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 100010
int sa[N],rk[N],height[N],t1[N],t2[N],c[N];
char s[N];
using namespace std;
bool cmp(int *y,int a,int b,int k){
    return y[a]==y[b]&&y[a+k]==y[b+k];
}
void DA(int n,int m){
    int *x=t1,*y=t2;
    for(int i=0;i<m;i++) c[i]=0;
    for(int i=0;i<n;i++) c[x[i]=s[i]]++;
    for(int i=1;i<m;i++) c[i]+=c[i-1];
    for(int i=n-1;~i;i--) sa[--c[x[i]]]=i;
    for(int k=1,p=0;k<=n;k*=2,m=p,p=0){
        for(int i=n-k;i<n;i++) y[p++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[y[i]]]++;
        for(int i=1;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;~i;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);p=1;x[sa[0]]=0;
        for(int i=1;i<n;i++)
            if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p-1;
            else x[sa[i]]=p++;
        if(p>=n) break;
    }
    for(int i=0;i<n;i++) rk[sa[i]]=i;
}
void get_ht(int n){
    for(int i=0,j,k=0;i<n;height[rk[i++]]=k){
        j=sa[rk[i]-1];k=k?k-1:0;
        while(s[i+k]==s[j+k]) k++;
    }
}
int solve(int n){
    long long sum=1LL*n*(n+1)/2;
    for(int i=1;i<=n;i++) sum-=(long long)height[i];
    return (int)sum;
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%s",s);int n=strlen(s);
        DA(n+1,128);
        get_ht(n);
        printf("%d\n",solve(n));
    }
    return 0;
}

 

Distinct Substrings(spoj 694)