给定一个字符串,求不相同子串个数。
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同子串个数。
总数为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; }