1. 程式人生 > >[BZOJ4516][SDOI2016]生成魔咒

[BZOJ4516][SDOI2016]生成魔咒

turn print for == bzoj ++i += gpo com

bzoj
luogu

題意

求一個串每個前綴中含有多少個不同字串
\(n\le100000\),字符集大小\(10^9\)

sol

後綴自動機的轉移開個\(map\)就好了。
每次插入以後,新增的貢獻就是\(len[last]-len[fa[last]]\)
累加即可。

code

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9'
)&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 2e5+5; int n,last=1,tot=1,fa[N],len[N];long long ans; map<int,int
>tr[N]; void extend(int c) { int v=last,u=++tot;last=u; len[u]=len[v]+1; while (v&&!tr[v][c]) tr[v][c]=u,v=fa[v]; if (!v) fa[u]=1; else { int x=tr[v][c]; if (len[x]==len[v]+1) fa[u]=x; else { int y=++tot; tr[y]=tr
[x]; fa[y]=fa[x];fa[x]=fa[u]=y;len[y]=len[v]+1; while (v&&tr[v][c]==x) tr[v][c]=y,v=fa[v]; } } } int main() { n=gi(); for (int i=1;i<=n;++i) { int x=gi(); extend(x); printf("%lld\n",ans+=len[last]-len[fa[last]]); } return 0; }

[BZOJ4516][SDOI2016]生成魔咒