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;
}
posted @ 2019-04-24 17:26  风浔凌  阅读(89)  评论(0编辑  收藏  举报