又被机房神犇肉丝哥哥和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的更多相关文章

  1. 51Nod 1600 Simple KMP 解题报告

    51Nod 1600 Simple KMP 对于一个字符串\(|S|\),我们定义\(fail[i]\),表示最大的\(x\)使得\(S[1..x]=S[i-x+1..i]\),满足\((x<i ...

  2. 51Nod 1600 Simple KMP SAM+LCT/树链剖分

    1600 Simple KMP 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i)显然对于一个字符串,如果我们将每个0<= ...

  3. 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*

    Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...

  4. 【51nod1006】simple KMP

    原题意看的挺迷糊的,后来看了http://blog.csdn.net/YxuanwKeith/article/details/52351335大爷的题意感觉清楚的多…… 做法也非常显然了,用树剖维护后 ...

  5. 51nod1600 Simple KMP

    题目描述 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i<=|S|看 ...

  6. HDU 6153 A Secret ( KMP&&DP || 拓展KMP )

    题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7 ...

  7. 51Nod 1277 字符串中的最大值(KMP,裸题)

    1277 字符串中的最大值 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如: ...

  8. CSU 2056 a simple game (正反进行KMP)超级好题!!!

    Description 这一天,小A和小B在玩一个游戏,他俩每人都有一个整数,然后两人轮流对他们的整数进行操作,每次在下列两个操作任选一个: (1)对整数进行翻转,如1234翻转成4321 ,1200 ...

  9. 51nod 1277字符串中的最大值(拓展kmp)

    题意: 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcd的所有前缀为a, ab, abc, abcd. 给出一个字符串S,求其所有前缀中,字符长度与出现次数的乘积的最大值.   题解 ...

随机推荐

  1. hdu4035 Maze (树上dp求期望)

    dp求期望的题. 题意: 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 从结点1出发,开始走,在每个结点i都有3种可能: 1.被杀死,回到结点1处(概率为ki) 2.找到出口,走出迷宫 ...

  2. out.print和out.write

    这是一个JSP页面: <%@ page language="java" import="java.util.*"  %> <%@ page p ...

  3. Scrapy学习-4-Items类&Pipelines类

    items类使用 作用 能使得我们非常方便的操作字段名 在items.py中定制我们的类 class ArticleItem(scrapy.Item): title = scrapy.Field() ...

  4. hanzi 全拼音 qu de

    Function pinyin(ByVal mystr As String, Optional types As Byte = 0) As StringDim temp   As String, i ...

  5. POJ 1509 Glass Beads【字符串最小表示法】

    题目链接: http://poj.org/problem?id=1509 题意: 求循环字符串的最小表示. 分析: 浅析"最小表示法"思想在字符串循环同构问题中的应用 判断两字符串 ...

  6. InteliJ 安装PlantUML插件

    打开InteliJ点击Setting 在[Plugins]搜索PlantUML插件,点击绿色的Install安装 然后重启 完成

  7. 使用uilabel重新自调整高度后显示横线和竖线问题

    这个使用uilabel自调节高度发现的问题,代码如下: //content label                        NSString *contentValue = ((Messag ...

  8. WIP - 离散任务点击组件-错误:LOCATOR.CONTROL 的变元无效:ORG_LOCATOR_CONTROL=''

    Getting Error "Invalid Argument to LOCATOR.CONTROL: ORG_LOCATOR_CONTROL='' in Material Requirem ...

  9. spring security原理图及其解释

    用户发出订单修改页面的请求,Access Decision Manager进行拦截,然后对比用户的授权和次页面需要的授权是不是有重合的部分,如果有重合的部分,那面页面就授权成功,如果失败就通知用户. ...

  10. spring-quartz定时任务使用小结

    在实际项目中,通常须要用到定时任务(定时作业).spring框架提供了非常好的实现. 1.  下载spring-quartz插件包 这里默认当前系统中是集成了spring框架的基本功能的.去网上下载s ...