51nod 1600 Simple KMP
又被机房神犇肉丝哥哥和glory踩爆了
首先这个答案的输出方式有点套路,当前的答案=上一个答案+每一个后缀的f值=上一个答案+上一次算的每个后缀的f值+当前每个后缀的深度
这个题意给了个根深度为-1有点诡异,考虑它的现实意义是这个后缀在前面出现了几次,这些后缀的深度和就是前面有多少子串和后缀是能匹配的
考虑用SAM把fail树搞出来,那么对于加入一个后缀,就是这个叶子到根的路径的点+1,询问也是问当前点到根的和
拿个LCT维护一下跑路
离线树剖好像更好写 肉丝早就跑路了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=1e5+_;
const LL mod=1e9+; struct node
{
int f,son[];
LL s,c;//子树内子串总出现数 子树内子串数
LL tot,num;//管理子串数,节点出现次数
LL lazy;
}tr[*maxn];
void update(int now)
{
int lc=tr[now].son[],rc=tr[now].son[];
tr[now].c=tr[lc].c+tr[rc].c+tr[now].tot;
tr[now].s=(tr[lc].s+tr[rc].s+tr[now].tot*tr[now].num+(tr[now].c-tr[now].tot)*tr[now].lazy)%mod;
}
void pushdown(int now)
{
int lc=tr[now].son[],rc=tr[now].son[];
if(lc!=)tr[lc].num+=tr[now].lazy,tr[lc].lazy+=tr[now].lazy,update(lc);
if(rc!=)tr[rc].num+=tr[now].lazy,tr[rc].lazy+=tr[now].lazy,update(rc);
tr[now].lazy=;
}
void rotate(int x,int w)
{
int f=tr[x].f,ff=tr[f].f;
int R,r; R=f,r=tr[x].son[w];
tr[R].son[-w]=r;
if(r!=)tr[r].f=R; R=ff,r=x;
if(tr[ff].son[]==f)tr[R].son[]=r;
else if(tr[ff].son[]==f)tr[R].son[]=r;
tr[r].f=R; R=x,r=f;
tr[R].son[w]=r;
tr[r].f=R; update(f);
update(x);
}
bool isroot(int x,int rt)
{
int f=tr[x].f;
if(f==rt|| tr[f].son[]!=x&&tr[f].son[]!=x )return true;
else return false;
}
int tt,tmp[*maxn];
void splay(int x,int rt)
{
int i=x; tt=;
while(!isroot(i,rt))
tmp[++tt]=i,i=tr[i].f;
tmp[++tt]=i;
while(tt>)
{
if(tr[tmp[tt]].lazy!=)pushdown(tmp[tt]);
tt--;
} while(!isroot(x,rt))
{
int f=tr[x].f,ff=tr[f].f;
if(isroot(f,rt))
{
if(tr[f].son[]==x)rotate(x,);
else rotate(x,);
}
else
{
if(tr[ff].son[]==f&&tr[f].son[]==x)rotate(f,),rotate(x,);
else if(tr[ff].son[]==f&&tr[f].son[]==x)rotate(f,),rotate(x,);
else if(tr[ff].son[]==f&&tr[f].son[]==x)rotate(x,),rotate(x,);
else if(tr[ff].son[]==f&&tr[f].son[]==x)rotate(x,),rotate(x,);
}
}
}
void access(int x)
{
int y=;
while(x!=)
{
splay(x,);
tr[x].son[]=y;
if(y!=)tr[y].f=x;
update(x);
y=x;x=tr[y].f;
}
}
void gotop(int x){access(x),splay(x,);}
void Link(int x,int y){gotop(x),tr[x].f=y;}
void Cut(int x)
{
gotop(x);
int lc=tr[x].son[];
tr[lc].f=;tr[x].son[]=;
update(x);
}
void add(int x)
{
gotop(x);
tr[x].num++;tr[x].lazy++;
update(x);
}
LL getsum(int x){gotop(x);return tr[x].s;}
void change(int x,LL tot)
{
gotop(x);
tr[x].tot=tot;
update(x);
} struct SAM
{
int w[],dep,fail;
}ch[*maxn];int cnt,last;
int gettot(int x){return ch[x].dep-ch[ch[x].fail].dep;}
LL insert(int k,int x)
{
int now=++cnt,pre=last; LL ret=;
ch[now].dep=k;
while(pre!=&&ch[pre].w[x]==)ch[pre].w[x]=now,pre=ch[pre].fail;
if(pre==)
{
ch[now].fail=;
change(now,gettot(now));
Link(now,ch[now].fail);
add(now);
}
else
{
int nxt=ch[pre].w[x];
if(ch[nxt].dep==ch[pre].dep+)
{
ch[now].fail=nxt;
change(now,gettot(now));
Link(now,ch[now].fail);
ret=getsum(now);
add(now);
}
else
{
int nnxt=++cnt; ch[nnxt]=ch[nxt];
ch[nnxt].dep=ch[pre].dep+;
ch[nxt].fail=nnxt; change(nxt,gettot(nxt));
tr[nnxt].num=tr[nxt].num;change(nnxt,gettot(nnxt));
Cut(nxt);
Link(nnxt,ch[nnxt].fail);
Link(nxt,ch[nxt].fail); //.......先处理nnxt和nxt....... ch[now].fail=nnxt;
change(now,gettot(now));
Link(now,ch[now].fail);
ret=getsum(now);
add(now); //........再搞nnxt和now....... while(pre!=&&ch[pre].w[x]==nxt)ch[pre].w[x]=nnxt,pre=ch[pre].fail;
}
}
last=now;
return ret;
} char ss[maxn];
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int n;
scanf("%d%s",&n,ss+); LL ans=,sum=;
cnt=last=;
for(int i=;i<=n;i++)
{
sum=(sum+insert(i,ss[i]-'a'+))%mod;
ans=(ans+sum)%mod;
printf("%lld\n",ans);
} return ;
}
51nod 1600 Simple KMP的更多相关文章
- 51Nod 1600 Simple KMP 解题报告
51Nod 1600 Simple KMP 对于一个字符串\(|S|\),我们定义\(fail[i]\),表示最大的\(x\)使得\(S[1..x]=S[i-x+1..i]\),满足\((x<i ...
- 51Nod 1600 Simple KMP SAM+LCT/树链剖分
1600 Simple KMP 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i)显然对于一个字符串,如果我们将每个0<= ...
- 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*
Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...
- 【51nod1006】simple KMP
原题意看的挺迷糊的,后来看了http://blog.csdn.net/YxuanwKeith/article/details/52351335大爷的题意感觉清楚的多…… 做法也非常显然了,用树剖维护后 ...
- 51nod1600 Simple KMP
题目描述 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i<=|S|看 ...
- HDU 6153 A Secret ( KMP&&DP || 拓展KMP )
题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7 ...
- 51Nod 1277 字符串中的最大值(KMP,裸题)
1277 字符串中的最大值 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如: ...
- CSU 2056 a simple game (正反进行KMP)超级好题!!!
Description 这一天,小A和小B在玩一个游戏,他俩每人都有一个整数,然后两人轮流对他们的整数进行操作,每次在下列两个操作任选一个: (1)对整数进行翻转,如1234翻转成4321 ,1200 ...
- 51nod 1277字符串中的最大值(拓展kmp)
题意: 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcd的所有前缀为a, ab, abc, abcd. 给出一个字符串S,求其所有前缀中,字符长度与出现次数的乘积的最大值. 题解 ...
随机推荐
- hdu 2713
#include<stdio.h> #include<string.h> int map[151000][2]; int max(int a,int b) { return ...
- request response session的常用方法
.request对象 客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应.它是HttpServletRequest类的实例. 序号 方 法 说 明 1 object ...
- msp430项目编程55
msp430综合项目---扩展项目五55 1.电路工作原理 2.代码(显示部分) 3.代码(功能实现) 4.项目总结
- MBP清除NVRAM和PRAM
Mac 会将某些设置存储在特定的存储区中,即使关机这些设置也不会丢失.在基于 Intel 的 Mac 上,存储位置是称为 NVRAM 的内存:而在基于 PowerPC 的 Mac 上,存储位置则是称为 ...
- HDU 5893 List wants to travel(树链剖分+线段树)
题目链接 HDU5893 $2016$年$ICPC$沈阳网络赛的$B$题.这道题其和 BZOJ2243 基本一样 那道题我也写了题解 点这里 两道题的区别就是$BZOJ$这题是点的权值,这道题是边权. ...
- JavaScript ES6中,export与export default
自述: 本来是对new Vue()和export default比较懵的,查了一下,发现我理解错了两者的关系,也没意识到export与export default的区别,先简单的记录一下基本概念,后续 ...
- 创建ROS工作空间和包
一.创建工作空间 mkdir -p ~/openni_ws/src cd ~/openni_ws catkin_make //在catkin工作空间(openni_ws)下catkin_ ...
- Java Enum枚举的用法(转)
说明:Java的枚举比dotnet的枚举好用,至少支持的方式有很多. 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以 ...
- SUPEROBJECT序列数据集为JSON
// SUPEROBJECT 序列数据集 cxg 2017-1-12// {"data":[{"c1":1,"c2":1}]};// DEL ...
- 异常来自 HRESULT:0x800A01A8
Windows 10 Enterprise Microsoft Office 2013 – Excel Oracle BI Publisher Desktop 11.1.1.7 异常来自 HRESUL ...