BZOJ4516: [Sdoi2016]生成魔咒

题意:给定n个将字符插至字符串尾的操作,求每次操作后本质不同的子串数。
题解: 一看“本质不同的子串”就知道是SAM啦,在建自动机时维护ans即可,注意数的值域过大要使用map。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read(){
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct SAM{
    map<int,int> trans;
    int maxl,minl,fa;
}sam[200005];
int n,m,las=1,tot=1;
ll ans=0;
int insert(int c,int u){
    int v=u,np=++tot;
    sam[np].maxl=sam[v].maxl+1;
    for (;v&&sam[v].trans[c]==0;v=sam[v].fa)
    sam[v].trans[c]=np;
    if (v==0){
        sam[np].minl=sam[np].fa=1; 
        ans+=sam[np].maxl-sam[np].minl+1;
        return np;
    }
    int x=sam[v].trans[c];
    if (sam[x].maxl==sam[v].maxl+1){
        sam[np].fa=x;
        sam[np].minl=sam[x].maxl+1;
        ans+=sam[np].maxl-sam[np].minl+1;
        return np;
    }
    int y=++tot;
    sam[y]=sam[x];
    ans-=sam[x].maxl-sam[x].minl+1;
    sam[y].maxl=sam[v].maxl+1;
    sam[y].minl=sam[sam[y].fa].maxl+1;
    sam[x].fa=sam[np].fa=y;
    sam[x].minl=sam[np].minl=sam[y].maxl+1;
    ans+=sam[x].maxl-sam[x].minl+1;
    ans+=sam[np].maxl-sam[np].minl+1;
    ans+=sam[y].maxl-sam[y].minl+1;
    for (;v&&sam[v].trans[c]==x;v=sam[v].fa)
    sam[v].trans[c]=y;
    return np;
}
int main(){
    n=read();
    for (int i=1;i<=n;i++){
    las=insert(read(),las);
    printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值