版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/84669546
SPOJ694传送门
SPOJ705传送门
解析:
后缀数组水题。
思路:
考虑每个后缀有多少个前缀是没有出现过的。
那么答案显然是 。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
cs int N=50004;
namespace SA{
char s[N];
int sa[N],rk[N],ht[N],bin[N],len;
inline void radix_sort(int *cs x,int *cs y,int m,int n);
inline void init();
inline void solve();
}
inline void SA::radix_sort(int *cs x,int *cs y,int m,int n){
memset(bin+1,0,sizeof(int)*m);
for(int re i=1;i<=n;++i)++bin[x[i]];
for(int re i=2;i<=m;++i)bin[i]+=bin[i-1];
for(int re i=n;i;--i)sa[bin[x[y[i]]]--]=y[i];
}
inline void SA::init(){
int *x=rk,*y=ht;
for(int re i=1;i<=len;++i)x[i]=s[i],y[i]=i;
int n=len,m=128;
radix_sort(x,y,m,n);
for(int re i=1,cnt=0;cnt<n;i<<=1){
cnt=0;
for(int re j=n-i+1;j<=n;++j)y[++cnt]=j;
for(int re j=1;j<=n;++j)if(sa[j]>i)y[++cnt]=sa[j]-i;
radix_sort(x,y,m,n);
swap(x,y);
x[sa[1]]=cnt=1;
for(int re j=2;j<=n;++j)x[sa[j]]=((y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i])?cnt:++cnt);
m=cnt;
}
for(int re i=1;i<=n;++i)rk[sa[i]]=i;
for(int re i=1,k=0,j;i<=len;ht[rk[i++]]=k)
for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}
inline void SA::solve(){
scanf("%s",s+1);
len=strlen(s+1);
s[len+1]='\0';
init();
ll ans=0;
for(int re i=1;i<=len;++i)ans+=len-sa[i]+1-ht[i];
printf("%lld\n",ans);
}
int T;
signed main(){
scanf("%d",&T);
while(T--)SA::solve();
return 0;
}