【题目分析】
后缀数组模板题。
由于height数组存在RMQ的性质。
那么对于一个后缀,与前面相同的串总共有h[i]+sa[i]个。然后求和即可。
【代码】(模板来自Claris,这个板子太漂亮了)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 500005
#define N 500005
#define inf 0x3f3f3f3f
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
void Finout()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
}
int Getint()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
struct Suffix_Array{
char s[maxn];
int rk[maxn],sa[maxn],h[maxn],tmp[maxn],cnt[maxn];
void build(int n,int m)
{
int i,j,k;n++;
F(i,0,2*5+4) rk[i]=sa[i]=h[i]=tmp[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
for (k=1;k<=n;k<<=1)
{
F(i,0,n-1)
{
j=sa[i]-k;
if (j<0) j+=n;
tmp[cnt[rk[j]]++]=j;
}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,n*sizeof(int));
memcpy(sa,tmp,n*sizeof(int));
if (j>=n-1) break;
}
for (j=rk[h[i=k=0]=0];i<n-1;++i,++k)
while (~k&&s[i]!=s[sa[j-1]+k]) h[j]=k--,j=rk[sa[j]+1];
}
}arr;
int main()
{
int tt;
scanf("%d",&tt);
while (tt--)
{
scanf("%s",arr.s);
int ans=0,l=strlen(arr.s);
arr.s[l]=0;
arr.build(l,128);
ans+=l-arr.sa[1];
F(i,2,l) ans+=l-arr.sa[i]-arr.h[i];
cout<<ans<<endl;
}
}
UPD(2017.3.30):回来再看自动机的时候重新写了一遍,感觉求h数组的部分不是很直观,所以改掉了。
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 5005
struct Suffix_Array{
int s[maxn];
int rk[maxn],cnt[maxn],sa[maxn],tmp[maxn],h[maxn];
void build(int n,int m)
{
int i,j,k; n++;
F(i,0,2*n+5) tmp[i]=sa[i]=rk[i]=h[i]=0;
F(i,0,m-1) cnt[i]=0;
F(i,0,n-1) cnt[rk[i]=s[i]]++;
F(i,1,m-1) cnt[i]+=cnt[i-1];
F(i,0,n-1) sa[--cnt[rk[i]]]=i;
for (k=1;k<=n;k<<=1)
{
F(i,0,n-1)
{
j=sa[i]-k;
if (j<0) j+=n;
tmp[cnt[rk[j]]++]=j;
}
sa[tmp[cnt[0]=0]]=j=0;
F(i,1,n-1)
{
if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,n*sizeof (int));
memcpy(sa,tmp,n*sizeof (int));
if (j>=n-1) break;
}
for (i=k=0;i<n;h[rk[i++]]=k)
for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
}
}SA;
char ss[maxn];
int ans=0,tt;
int main()
{
scanf("%d",&tt);
while (tt--)
{
ans=0;
scanf("%s",ss);
int n=strlen(ss);
F(i,0,n-1) SA.s[i]=ss[i]; SA.s[n]=0;
SA.build(n,256);
F(i,1,n) ans+=n-SA.sa[i]-SA.h[i];
printf("%d
",ans);
}
}