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,求其所有前缀中,字符长度与出现次数的乘积的最大值. 题解 ...
随机推荐
- java面试题之stop()和suspend()方法为何不不推荐使⽤?
stop方法:他是不安全的,他会停止所有运行中的线程: suspend方法:容易发生死锁,虽然调用suspend方法目标线程会停下来,但是仍然持有之前的锁,其他线程都不能访问锁定的资源,就会造成死锁, ...
- 路飞学城详细步骤 part2
一 显示课程列表 需求:当你点击课程,course.vue在 <router-view>渲染,并不需要你进行其他点击,所欲的课程列表直接在前端显示,数据是从数据库拿到的. 补充1:生命周期 ...
- Jackson转换JSON例子
Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 前面有介绍过json-lib这个框架,在线博文:http://www.cnblo ...
- codevs——1958 刺激
1958 刺激 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description saffah的一个朋友S酷爱滑雪,并且追求刺 ...
- easyui分页时,总页数出错
错误出现 MyBatis用easyui写后台分页代码时,出现翻页后显示总页数错误 代码如下 可能原因在于后台mappers.xml里的sql语句错误 <select id="getPr ...
- error MIDL2311 解决方法
error MIDL2311 : statements outside library block are illegal in mktyplib compatability mode : [] 在编 ...
- Go -- 今日头条架构
夏绪宏,今日头条架构师,专注对高性能大规模 Web 架构,云计算.性能优化.编程语言理论等方向,PHP committer,HHVM 项目贡献者.2009 加入百度,先后从事大规模 IDC 自运维设施 ...
- linux shell简单实现数据库自动备份
以centos系统为例,实现数据库自动备份.1.写一个shell: 12 #! /bin/bashmysqldump -cp --user=root --password='123' dbName | ...
- 出现异常时直接把e输出比输出e.getMessage()好得多
之前研究态度不好,出异常时处理草草了事,今天出现问题才觉得该认真对待每个分支.
- linux系统之shell编程-正則表達式
shell编程正則表達式: 1:元字符 [ ] . * ? + ( ) | { } ^ $ 2 : [a-z0-9] 表示匹配随意数字和字母的一个 3 : [^a-z] ...