Given a string, we need to find the total number of its distinct
substrings. InputT- number of test cases. T<=20; Each test case consists of one string,
whose length is <= 1000 OutputFor each test case output one number saying the number of distinct
substrings.
跑完后缀数组以后,后缀sa[i]总共有n-sa[i]+1个前缀,其中有height[i]个重复,所以答案是sigma(n-sa[i]-height[i]+1)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[1010];
int a[1010],sa[1010],rank[1010],height[1010],cnt[1010],ord[1010],t1[1010],t2[1010],n;
int main()
{
int T,i,j,k,m,p,q,*x=t1,*y=t2,ans;
scanf("%d",&T);
while (T--)
{
memset(a,0,sizeof(a));
scanf("%s",s+1);
n=strlen(s+1);
for (i=1;i<=n;i++)
ord[i]=s[i];
sort(ord+1,ord+n+1);
m=unique(ord+1,ord+n+1)-ord-1;
for (i=1;i<=n;i++)
a[i]=lower_bound(ord+1,ord+m+1,s[i])-ord;
for (i=1;i<=m;i++)
cnt[i]=0;
for (i=1;i<=n;i++)
cnt[x[i]=a[i]]++;
for (i=2;i<=m;i++)
cnt[i]+=cnt[i-1];
for (i=n;i;i--)
sa[cnt[x[i]]--]=i;
for (k=1;k<=n;k<<=1)
{
p=0;
for (i=n-k+1;i<=n;i++)
y[++p]=i;
for (i=1;i<=n;i++)
if (sa[i]-k>=1)
y[++p]=sa[i]-k;
for (i=1;i<=m;i++)
cnt[i]=0;
for (i=1;i<=n;i++)
cnt[x[y[i]]]++;
for (i=2;i<=m;i++)
cnt[i]+=cnt[i-1];
for (i=n;i;i--)
sa[cnt[x[y[i]]]--]=y[i];
swap(x,y);
p=x[sa[1]]=1;
for (i=2;i<=n;i++)
{
if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) p++;
x[sa[i]]=p;
}
if ((m=p)>=n) break;
}
for (i=1;i<=n;i++)
rank[sa[i]]=i;
for (i=1,k=0;i<=n;i++)
{
if (k) k--;
if (rank[i]==1)
{
k=0;
continue;
}
while (a[i+k]==a[sa[rank[i]-1]+k]) k++;
height[rank[i]]=k;
}
ans=0;
for (i=1;i<=n;i++)
ans+=n-sa[i]-height[i]+1;
printf("%d\n",ans);
}
}