我们可以想到这样的一种计数方法:
后缀[n,n]:有多少个不同串
后缀[n-1,n]:有多少个不同串
后缀[n-2,n]:有多少个不同串
…
最后答案减去重复的串。(发现无法统计答案)
那么改变一下顺序,将这些后缀按照字典序排序后,我们也可以得到另一种顺序来进行计数:
字典序第一小的后缀:有多少个不同串
字典序第二小的后缀:有多少个不同串
字典序第三小的后缀:有多少个不同串
…
我们可以发现,排序以后的,i从2开始,第i个串和第i-1个串,他们相同的串的个数,就是height[i]。
而初始,串的个数一共为:n*(n+1)/2
那么,我们减去相同串个数,即为答案。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,m,ans;
int sum[N],rk[N],rk2[N],tp[N],sa[N],height[N];
char s[N];
inline void qsort()
{
for (register int i=0; i<=m; ++i) sum[i]=0;
for (register int i=1; i<=n; ++i) sum[rk[i]]++;
for (register int i=1; i<=m; ++i) sum[i]+=sum[i-1];
for (register int i=n; i>=1; --i) sa[sum[rk[tp[i]]]]=tp[i],sum[rk[tp[i]]]--;
}
inline void SA()
{
m=130;
for (register int i=1; i<=n; ++i) rk[i]=s[i]-'0'+1,tp[i]=i;
qsort();
int p=0;
for (register int len=1; p<n; m=p,len<<=1)
{
p=0;
for (register int i=n-len+1; i<=n; ++i) tp[++p]=i;
for (register int i=1; i<=n; ++i) if (sa[i]>len) tp[++p]=sa[i]-len;
qsort();
memcpy(rk2,rk,sizeof(rk2));
p=1; rk[sa[1]]=p;
for (register int i=2; i<=n; ++i)
{
if (rk2[sa[i]]==rk2[sa[i-1]] && rk2[sa[i]+len]==rk2[sa[i-1]+len]) p=p; else p++;
rk[sa[i]]=p;
}
}
}
inline void LCP()
{
for (register int i=1; i<=n; ++i) rk[sa[i]]=i;
int k=0;
for (register int i=1; i<=n; ++i)
{
if (rk[i]==1) continue;
if (k) k--;
int j=sa[rk[i]-1];
while (i+k<=n && j+k<=n && s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
signed main(){
scanf("%lld",&n);
scanf("%s",s+1);
SA();
LCP();
ans=n*(n+1)/2;
for (register int i=2; i<=n; ++i) ans-=height[i];
printf("%lld\n",ans);
return 0;
}