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程序性能优化之缓冲优化
优化前的代码: package com; import javax.swing.*; import java.awt.*; /** * 使用Eclipse,右键Run As,Java Applet运行 ...
- mock数据。根据表中一天的数据模拟其他日期的数据
package test; import java.sql.*; import java.text.SimpleDateFormat; import java.util.*; import java. ...
- 【HDOJ5949】Relative atomic mass(签到)
题意:给定一个只由H.C.O三种分子组成物质的分子式,求相对分子质量 len<=10 思路:队友写的 #include <stdio.h> #include <vector&g ...
- 51nod1026 矩阵中不重复的元素 V2
$n \leq 500000,m \leq 500000$的矩阵,第一行第一列是$a^b,2 \leq a,b \leq 500000$,如果一个数是$i^j$那他右边是$i^{j+1}$,下面是${ ...
- gridview无数据源实现更新数据库(即断开更新数据库)
原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- 重写enum的valueof方法等
enum 对象的常用方法介绍 int compareTo(E o) 比较此枚举与指定对象的顺序. Class<E> getDeclaringClass() ...
- 使用注解开发springmvc
1.导入jar包 commons-logging-1.2.jar spring-aop-4.3.6.RELEASE.jar spring-beans-4.3.6.RELEASE.jar spring- ...
- BZOJ——1626: [Usaco2007 Dec]Building Roads 修建道路
http://www.lydsy.com/JudgeOnline/problem.php?id=1626 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1 ...
- nginx原配置
#原配置 server { listen ; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main ...
- Spring实战Day5
3.3自动装配bean的歧义性 产生歧义的原因 找到多个符合条件的组件,如下注入talent时会有两个满足条件的组件 解决方法 标示首选的bean,但是同时标示两个或多个同样会存在歧义 自动装配标示P ...