题意:统计本质不同的子串数量。
题解:模板题,后缀自动机。在每一个节点处,统计一下他能代表多少个 以他为终点的串。然后动态创建SAM,同时每加一次都输出一次就行了。唯一的不同是,这个题是int,而不是传统的字符串,那么把nxt数组换成map,复杂度多一个log(sizeof[nxt]),实际上非常小。
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
long long ans=0;
struct SAM{
int last,cnt,fa[maxn*2],len[maxn*2];
map<int,int> nxt[maxn*2];
void init(){
last=cnt=1;
}
void add(int c){
int p = last;
int np = ++cnt;
last =np;
len[np] = len[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] =np;
p=fa[p];
}
if (!p){
fa[np]=1;
}else{
int q = nxt[p][c];
if (len[q]==len[p]+1){
fa[np] =q;
}else{
int nq =++cnt;
len[nq]=len[p]+1;
nxt[nq]=nxt[q];
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p=fa[p];
}
}
}
ans+=len[last]-len[fa[last]];
}
}sam;
int main(){
int n;
sam.init();
scanf("%d",&n);
while (n--){
int temp;
scanf("%d",&temp);
sam.add(temp);
printf("%lld\n",ans);
}
return 0;
}