题意:求本质不同的子串数。
(SAM+DP)
答案即为路径条数。
我们设 (f[u]) 表示从 (u) 出发的路径条数:(f[u]=1+sum_{(u,v,ch)} f[v]) ,其中 (1) 代表空串。
最后答案即为 (f[0]-1)
(SAM+parent树)
每个子串只会出现一次,并且每个点的 (sz) 即为 (maxlen[u]-minlen[u]) 。
答案为 (sum len[u]-len[fa[u]])
#include<iostream>
#include<cstdio>
#include<cstring>
#include<unordered_map>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
}
const int N=100010;
int n,tot=1,lst=1;
int fa[N],len[N];
ll ans;
unordered_map<int,int> c[N];
inline void add(int ch) {
R p=lst,np=lst=++tot;
len[np]=len[p]+1;
for(;p&&!c[p].count(ch);p=fa[p]) c[p][ch]=np;
if(!p) fa[np]=1;
else {
R q=c[p][ch];;
if(len[q]==len[p]+1) fa[np]=q;
else {
R nq=++tot;
c[nq]=c[q];
fa[nq]=fa[q],len[nq]=len[p]+1;
fa[q]=fa[np]=nq;
for(;p&&c[p].count(ch)&&c[p][ch]==q;p=fa[p]) c[p][ch]=nq;
}
}
printf("%lld
",ans+=len[np]-len[fa[np]]);
}
inline void main() {
n=g();
for(R i=1;i<=n;++i) add(g());
}
} signed main() {Luitaryi::main(); return 0;}
2019.01.09