题意:求一个字符串中互不相同的子串的个数
解法:后缀数组
思考为什么会有重复?因为后缀之间有lcp。
如何去除重复?某一后缀的某部分前缀不与其他后缀构成lcp的时候这部分才有贡献。
这也就是说,如果按字典序遍历所有后缀,一个后缀的lcp不为空,那么lcp构成的子串肯定在之前被统计过。
可以用下图的例子感受一下,
#include<iostream>
#include<cstdio>
#include<ctype.h>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n,m;
int height[maxn];
char s[maxn];
int rak[maxn],sa[maxn],tp[maxn],tax[maxn];
void bucket() //桶排序
{
for(int i=0; i<=m; ++i) tax[i]=0;
for(int i=1; i<=n; ++i) tax[rak[i]]++;
for(int i=1; i<=m; ++i) tax[i]+=tax[i-1];
for(int i=n; i>=1; i--)
sa[tax[rak[tp[i]]]--]=tp[i];
}
void get_sa()
{
m=128;
for(int i=1; i<=n; i++) rak[i]=s[i],tp[i]=i;
bucket();
for(int w=1,p=0; p<n; m=p,w<<=1)
{
p=0;
for(int i=1; i<=w; i++) tp[++p]=n-w+i;
for(int i=1; i<=n; i++)
if(sa[i]>w) tp[++p]=sa[i]-w;
bucket();
swap(tp,rak);
rak[sa[1]]=p=1;
for(int i=2;i<=n;++i)
rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]] && tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}
}
void get_height()
{
int k=0;
for(int i=1;i<=n;++i)
{
if(k) k--;
int j=sa[rak[i]-1];
while(s[i+k]==s[j+k]) ++k;
height[rak[i]]=k;
}
}
int main()
{
cin>>n;
cin>>s+1;
get_sa();
get_height();
ll ans=1ll*n*(n+1)/2; //总子串个数
for(int i=1; i<=n; i++)
ans-=height[rak[i]];
cout<<ans<<endl;
return 0;
}