luogu P4070 [SDOI2016]生成魔咒

首先有两个结论:
1.后缀自动机具有最简性,即每种不同的子串只会在sam上体现一次,体现形式是sam上一条由root出发的路径。
2.一个字符串不同子串的个数等于所有关键节点的max(x)-min(x)+1。证明就是考虑后缀自动机的最简性。

然后,这就是个水题了。
每次插入一个字符后,更新答案即可。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<map>
#include<cstdlib>
#include<algorithm>
#define N 330000
#define L 300000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
char ch[N];
bool flag[N];
int root=1,size=1,last=1,id[N];
struct node{int len,link;map<int,int>nxt;}s[N];
void insert(int k)
{
    int cur=++size,p=last;
    s[cur].len=s[p].len+1;
    while(p&&!s[p].nxt[k])
    {
        s[p].nxt[k]=cur;
        p=s[p].link;
    }
    last=cur;
    if(!p){s[cur].link=root;return;}
    int q=s[p].nxt[k];
    if(s[q].len==s[p].len+1)s[cur].link=q;
    else
    {
        int clone=++size;
        s[clone]=s[q];
        s[clone].len=s[p].len+1;
        while(p&&s[p].nxt[k]==q)
        {
            s[p].nxt[k]=clone;
            p=s[p].link;
        }
        s[q].link=s[cur].link=clone;
    }
}
int main()
{
    ll ans=0;
    int n=read();
    for(int i=1;i<=n;i++)
    {
        int x=read();
        insert(x);
        ans+=s[last].len-s[s[last].link].len;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Creed-qwq/p/10159601.html