题目:
题解:
对于一个状态s,他的right集合代表的子串的长度就是(len[fa],len[s]]。这道题我们需要动态的维护不同子串的个数,每次从头扫一遍直接计算肯定不行,我们考虑加入一个新字符会产生多少新的不同子串,这个个数其实就是(len[fa],len[s]]的区间长度。
代码:
#include <map>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=200005;
int cnt,last,np,p,q,nq,fa[N*2],step[N*2];
long long ans;
map <int,int> ch[N*2];
void insert(int c)
{
p=last; last=np=++cnt;
step[np]=step[p]+1;
while (p && !ch[p][c]) ch[p][c]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
q=ch[p][c];
if (step[q]==step[p]+1) fa[np]=q;
else
{
nq=++cnt; step[nq]=step[p]+1;
ch[nq]=ch[q];
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
while (ch[p][c]==q) ch[p][c]=nq,p=fa[p];
}
}
ans+=step[np]-step[fa[np]];
}
int main()
{
int n;scanf("%d",&n);
last=cnt=1;int w;
for (int i=1;i<=n;i++)
{
scanf("%d",&w);
insert(w);
printf("%lld\n",ans);
}
}