bzoj4516 / P4070 [SDOI2016]生成魔咒
后缀自动机
每插入一个字符,对答案的贡献为$len[last]-len[fa[last]]$
插入字符范围过大,所以使用$map$存储。
(去掉第35行就是裸的板子了。)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cctype> 5 #include<map> 6 using namespace std; 7 void read(int &x){ 8 static char c=getchar();x=0; 9 while(!isdigit(c)) c=getchar(); 10 while(isdigit(c)) x=x*10+(c^48),c=getchar(); 11 } 12 #define N 100005 13 long long ans; 14 struct Sam{ 15 int fa[N<<1],len[N<<1]; 16 int last,ed,p,q; 17 map <int,int> nxt[N<<1]; 18 Sam(){last=ed=1;} 19 void init(){ 20 int n,c; read(n); 21 while(n--) read(c),add(c),printf("%lld\n",ans); 22 } 23 void add(int c){ 24 p=last; len[last=++ed]=len[p]+1; 25 for(;p&&!nxt[p][c];p=fa[p]) nxt[p][c]=ed; 26 if(!p) fa[ed]=1; 27 else{ 28 q=nxt[p][c]; 29 if(len[q]==len[p]+1) fa[ed]=q; 30 else{ 31 len[++ed]=len[p]+1; nxt[ed]=nxt[q]; 32 fa[ed]=fa[q]; fa[q]=fa[ed-1]=ed; 33 for(;nxt[p][c]==q;p=fa[p]) nxt[p][c]=ed; 34 } 35 }ans+=len[last]-len[fa[last]];//对答案的贡献 36 } 37 }sam; 38 int main(){sam.init(); return 0;}