SPOJ694 Distinct Substrings

【题意】

求不相同的子串的个数

【分析】

考虑每一个后缀的前缀表示了所有的子串,有n*(n+1)/2个

减去重复的即可,也就是所有的height之和

【代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e3+5;
int n,T;
char a[maxn];
int h[maxn],maxi,id[maxn];
int sa[maxn],rk[maxn],oldrk[maxn],cnt[maxn],fz[maxn];
bool cmp(int x,int y,int w)
{
    return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void calcsa()
{
    int m=233;
    for(int i=0;i<=m;i++) cnt[i]=0;
    for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++;
    for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
    int i,p;
    for(int w=1;;w<<=1,m=p)
    {
        for(p=0,i=n;i>n-w;i--) id[++p]=i;
        for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
        for(i=0;i<=m;i++) cnt[i]=0;
        for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++;
        for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i];
        for(i=1;i<=n;i++) oldrk[i]=rk[i];
        for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
        if(p==n)
        {
            for(i=1;i<=n;i++) sa[rk[i]]=i;
            break;
        }
    }
}
long long sumh=0;
void calch()
{
    int i,k=0;
    sumh=0;
    for(i=1;i<=n;i++)
    {
        if(k) k--;
        while(a[i+k]==a[sa[rk[i]-1]+k]) k++;
        h[rk[i]]=k;
        sumh+=k;
    }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%s",a+1);
        n=strlen(a+1);
        calcsa(); calch();
        long long ans=1LL*(n+1)*n/2;
        printf("%lld\n",ans-sumh);
    }
    return 0;
}

 

posted @ 2021-04-27 19:27  andyc_03  阅读(33)  评论(0编辑  收藏  举报