SDOI2016 生成魔咒
题目链接:戳我
求不同的子串个数(相同但出现在不同位置的算一个)——就是一个SAM裸题啦!
我们直接一个一个添加节点的时候统计答案即可(每次多出来的都是last里面存的)
但是数太大了,记得要map或者离散化哦qwq
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define MAXN 200010
using namespace std;
int n,m,tot=1,last=1,cnt;
long long ans;
// map<int,int>ex;
struct Node
{
int ff,len;
map<int,int>ch;
}t[MAXN<<1];
inline void extend(int c)
{
int p=last,np=++tot;last=np;
t[np].len=t[p].len+1;
while(p&&!t[p].ch.count(c)) t[p].ch[c]=np,p=t[p].ff;
if(!p) t[np].ff=1;
else
{
int q=t[p].ch[c];
if(t[q].len==t[p].len+1) t[np].ff=q;
else
{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[np].ff=t[q].ff=nq;
while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].ff;
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int cur;
scanf("%d",&cur);
// if(!ex.count(cur)) ex[cur]=++cnt;
extend(cur);
ans+=t[last].len-t[t[last].ff].len;
printf("%lld\n",ans);
}
return 0;
}