Luogu P4070 [SDOI2016]生成魔咒
题意:求本质不同的子串数。
\(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\n",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