给你一个长度不超过 100000 的字符串(小写字母)
求不同子串的个数
题解:后缀数组
每个子串一定是某个后缀的前缀,及等价于求后缀之间不相同前缀的个数
每个后缀可以提供 (n+1-sa[i])个子串,其中有height[i]个重复
/*
Algorithm: 后缀数组求 不同子串的个数
Author: anthony1314
Creat Time:2019.4.18
Time Complexity:
*/
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 100005
#define mod 1e9 + 7
#define line printf("--------------");
#define maxn 100005
using namespace std;
int n,m,sa[maxn],rk[maxn],tp[maxn],tax[maxn],p;
int height[maxn],T;
char s[maxn];
long long ans;
void Qsort() {
for(int i=0; i<=m; i++) {
tax[i]=0;
}
for(int i=1; i<=n; i++) {
tax[rk[i]]++;
}
for(int i=1; i<=m; i++) {
tax[i]+=tax[i-1];
}
for(int i=n; i>=1; i--) {
sa[ tax[rk[tp[i]]]-- ]=tp[i];
}
}
void get_height(int n) {
int k=0,j;
for(int i=1; i<=n; i++) {
j=sa[rk[i]-1];
if(k) {
k--;
}
while(s[j+k]==s[i+k]) {
k++;
}
height[rk[i]]=k;
}
}
int main() {
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1; i<=n; i++) {
rk[i]=s[i]-'a';
tp[i]=i;
}
m=105;
Qsort();
for(int ws=1,p=0; p<n; m=p,ws<<=1) {
p=0;
for(int i=1; i<=ws; i++) {
tp[++p]=n-ws+i;
}
for(int i=1; i<=n; i++) {
if(sa[i]>ws)tp[++p]=sa[i]-ws;
}
Qsort();
swap(tp,rk);
rk[sa[1]]=p=1;
for(int i=2; i<=n; i++) {
rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+ws]==tp[sa[i]+ws])?p:++p;
}
}
get_height(n);
ans=0;
for(int i=1; i<=n; i++) {
ans+=n+1-sa[i]-height[i];
}
printf("%lld\n",ans);
return 0;
}