SPOJ Distinct Substrings

给定一个字符串,求不相同子串个数。
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同子串个数。
总数为n*(n-1)/2,再减掉height[i]的和就是答案

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+14;
int sa[maxn];
int t1[maxn];
int t2[maxn];
int c[maxn];
int rk[maxn];
int height[maxn];
void build_sa (int s[],int n,int m) {
    int i,j,p;
    int *x=t1,*y=t2;
    for (i=0;i<m;i++) c[i]=0;
    for (i=0;i<n;i++) c[x[i]=s[i]]++;
    for (i=1;i<m;i++) c[i]+=c[i-1];
    for (i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for (j=1;j<=n;j<<=1) {
        p=0;
        for (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<m;i++) c[i]=0;
        for (i=0;i<n;i++) c[x[y[i]]]++;
        for (i=1;i<m;i++) c[i]+=c[i-1];
        for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for (i=1;i<n;i++) 
        x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
        if (p>=n) break;
        m=p; 
    }
}
void getHeight (int s[],int n) {
    int i,j,k=0;
    for (i=0;i<=n;i++) rk[sa[i]]=i;
    for (i=0;i<n;i++) {
        if (k) k--;
        j=sa[rk[i]-1];
        while (s[i+k]==s[j+k]) k++;
        height[rk[i]]=k;
    }
}
bool check (int n,int k,int t) {
    int num=1;
    for (int i=2;i<=n;i++) {
        if (height[i]>=t) {
            num++;
            if (num>=k) return true;
        }
        else num=1;
    }
    return false;
}
char str[maxn];
int s[maxn];
int main () {
    int T;
    scanf ("%d",&T);
    while (T--) {
        scanf ("%s",str);
        int n=strlen(str);
        for (int i=0;i<=n;i++) s[i]=str[i];
        build_sa(s,n+1,128);
        getHeight(s,n);
        int ans=n*(n+1)/2;
        for (int i=2;i<=n;i++) ans-=height[i];
        printf ("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhanglichen/p/12332660.html