Repeated Substrings(UVAlive 6869)
题意:求出现过两次以上的不同子串有多少种。
/* 用后缀数组求出height[]数组,然后扫一遍, 发现height[i]-height[i-1]>=0,就ans+=height[i]-height[i-1]。 */ #include<cstdio> #include<iostream> #include<cstring> #define N 100010 using namespace std; int sa[N],rk[N],ht[N],t1[N],t2[N],c[N],n,m=128; char s[N]; bool cmp(int *y,int a,int b,int k){ int a1=y[a],b1=y[b]; int a2=a+k>=n?-1:y[a+k]; int b2=b+k>=n?-1:y[b+k]; return a1==b1&&a2==b2; } void DA(){ 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; } } void get_ht(){ for(int i=0;i<n;i++) rk[sa[i]]=i; for(int i=0,k=0;i<n;ht[rk[i++]]=k){ if(!rk[i]) continue; int j=sa[rk[i]-1];k=k?k-1:k; while(j+k<n&&i+k<n&&s[j+k]==s[i+k]) k++; } ht[0]=0; } int main(){ int T;scanf("%d",&T); while(T--){ memset(s,0,sizeof(s)); memset(ht,0,sizeof(ht)); m=128; scanf("%s",s); n=strlen(s); DA();get_ht(); long long ans=0; for(int i=1;i<n;i++) if(ht[i]>ht[i-1]) ans+=(long long)(ht[i]-ht[i-1]); cout<<ans<<endl; } return 0; }