P4070 [SDOI2016] 生成魔咒

P4070 [SDOI2016] 生成魔咒

题目描述

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1,2 拼凑起来形成一个魔咒串 [1,2]

一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。

例如 S=[1,2,1] 时,它的生成魔咒有 [1],[2],[1,2],[2,1],[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1],[1,1],[1,1,1] 三种,最初 S 为空串。

共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都需要求出,当前的魔咒串 S 共有多少种生成魔咒。

数据规模与约定

对于 100% 的数据,保证 1n1051xi109

说句闲话:

Solution:

十分模板的一道题,每加进来一个数字,我们就在 sam 上将其 insert 那么每次答案统计就是 maxlenxmaxlenfa。为什么是这个?因为我们每次在 sam 上 insert 一个数 ai 时,会产生 i 个新串(以 [1,i] 为左端点, i 为右端点)。那么我们求出fa其实代表着这些串中哪些是旧的(其实就是 rt->fa 能代表的所有串都是重复的,[minlenx,maxlenx] 是新的)。二者作差,得到本次新增的答案。

Code:

#include<bits/stdc++.h>
#define ll long long
const int N=2e5+5;
using namespace std;
int n,m;
ll ans;
struct SAM{
map<int,int> ch[N];
int len[N],fa[N];
int last,cnt;
void init(){last=cnt=1;}
inline void insert(int c)
{
int p=last,q=++cnt;len[q]=len[p]+1;last=q;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=q;
if(!p){fa[q]=1;return;}int x=ch[p][c];
if(len[x]==len[p]+1){fa[q]=x;return;}
int y=++cnt;len[y]=len[p]+1;fa[y]=fa[x];ch[y]=ch[x];
for(;p&&ch[p][c]==x;p=fa[p])ch[p][c]=y;
fa[x]=fa[q]=y;
}
inline void calc(){ans+=len[last]-len[fa[last]];}
}sam;
void work()
{
cin>>n;
sam.init();
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
sam.insert(x);sam.calc();
printf("%lld\n",ans);
}
}
int main()
{
//freopen("incantation.in","r",stdin);freopen("incantation.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示