求不同子串个数
解题思路
这个其实就是在后缀自动机上统计不同的路径条数,可以\(dp\)解决,\(f[u]=\sum\limits_{v=son[u]} f[v]+1\),时间复杂度\(O(n)\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
typedef long long LL;
inline int rd(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,c[N],a[N],l[N],r[N],len;
LL f[N];
char s[N];
struct SAM{
int ch[N][28],fa[N],cnt,lst,l[N];
void insert(int c){
int p=lst,np=++cnt; lst=np; l[np]=l[p]+1;
for(;!ch[p][c] && p;p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(l[q]==l[p]+1) fa[np]=q;
else {
int nq=++cnt; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void build(){
for(int i=1;i<=n;i++) insert(s[i]-'a'+1);
for(int i=1;i<=cnt;i++) c[l[i]]++;
for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
}
void solve(){
for(int i=cnt;i;i--)
for(int j=1;j<=26;j++)
if(ch[a[i]][j]) f[a[i]]+=f[ch[a[i]][j]]+1;
printf("%lld\n",f[1]);
}
}sam;
int main(){
sam.lst=sam.cnt=1; n=rd();
scanf("%s",s+1); sam.build();
sam.solve();
return 0;
}