当前位置: 首页 > news >正文

【YBT2023寒假Day14 C】字符串题(SAM)(树链剖分)(线段树)

字符串题

题目链接:YBT2023寒假Day14 C

题目大意

对于一个字符串 S 定义 F(S) 是 fail 树上除了 0 点其它点的深度和。
G(S) 是 S 每个子串 S’ 的 F(S’) 之和。
然后一个空串,每次在后面加一个字符,要你维护这个串的 G 值。

思路

考虑把 G(S[1,x])G(S[1,x])G(S[1,x]) 值差分一下,会发现 G(S[1,i])−G(S[1,i−1])G(S[1,i])-G(S[1,i-1])G(S[1,i])G(S[1,i1]) 的值其实是以 iii 为结尾的子串的 FFF 值之和。
那从子串变成了一个后缀,看起来就可做很多了,考虑怎么算。

那我们看 fail 树性质,一个字符串 SSSjjjiii 的祖先当且仅当 S[1,j]=S[i−j+1,i]S[1,j]=S[i-j+1,i]S[1,j]=S[ij+1,i]
F(S)F(S)F(S) 就是满足 S[1,j]=S[i−j+1]S[1,j]=S[i-j+1]S[1,j]=S[ij+1]1⩽j<i1\leqslant j<i1j<i(i,j)(i,j)(i,j) 对数。
那也就是在 SSS 里面选一个前缀,再选一个非前缀,它们相等的方案数。

注意到我们要求的是以 iii 结尾的 FFF 值之和,那开头就不固定,结尾是固定的。
FFF 值是选一个前缀,再一个非前缀,那这个是开头固定,结尾不固定。
那你这个开头固定放在开头不固定里,它不固定了,你这个结尾不固定在结尾固定里面肯定也是不固定。
所以头尾都不固定,只需要两个不是同一个位置的字符串相等即可。
那答案就是所有本质不同的子串的出现次数 xxx(x2)\binom{x}{2}(2x) 之和。


那注意到不需要在线,我们可以先建出最后的后缀树。
那我们用一个 dxd_xdx 表示每个点 xxx 对于子串的出现次数。
那插入就是把它到祖先路径的 dxd_xdx 加一,询问就是所有点的 endpos 大小乘 (dx2)\binom{d_x}{2}(2dx)
那这个维护这个和不难,我们记录着这个和 sumsumsum,每次要插入的时候,每个新贡献的值就是它 endpos 集合大小乘上 dxd_xdx(这个 dxd_xdx 还没加 111),然后你再把 dxd_xdx 加一。
那这个是路径加值,路径求和,直接树链剖分线段树维护即可。
复杂度 O(nlog⁡2n)O(n\log ^2n)O(nlog2n)


ex:
如果强制在线,我们也可以用 LCT 来维护这棵树,那就也是同样的操作,复杂度 O(nlog⁡n)O(n\log n)O(nlogn)

代码

#include<cstdio>
#include<vector>
#define ll long long
#define mo 1000000007using namespace std;const ll N = 4e5 + 100;
ll n, fa[N], sz[N], son[N], dfn[N], top[N], dy[N];
ll lst = 1, tot = 1, pla[N]; 
char s[N];struct node {ll son[26], len, fa;
}d[N];struct XD_tree {ll num[N << 2], f[N << 2], lzy[N << 2];void up(ll now) {num[now] = (num[now << 1] + num[now << 1 | 1]) % mo;f[now] = (f[now << 1] + f[now << 1 | 1]) % mo;}void downa(ll now, ll x) {(f[now] += x * num[now] % mo) %= mo;(lzy[now] += x) %= mo;}void down(ll now) {if (lzy[now]) {downa(now << 1, lzy[now]); downa(now << 1 | 1, lzy[now]);lzy[now] = 0;}}void build(ll now, ll l, ll r) {if (l == r) {num[now] = d[dy[l]].len - d[d[dy[l]].fa].len;return ;}ll mid = (l + r) >> 1;build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);up(now);}void update(ll now, ll l, ll r, ll L, ll R, ll x) {if (L <= l && r <= R) {downa(now, x); return ;}ll mid = (l + r) >> 1; down(now);if (L <= mid) update(now << 1, l, mid, L, R, x);if (mid < R) update(now << 1 | 1, mid + 1, r, L, R, x);up(now);}ll query(ll now, ll l, ll r, ll L, ll R) {if (L <= l && r <= R) return f[now];ll mid = (l + r) >> 1; down(now); ll re = 0;if (L <= mid) (re += query(now << 1, l, mid, L, R)) %= mo;if (mid < R) (re += query(now << 1 | 1, mid + 1, r, L, R)) %= mo;return re;}
}T;struct SLPF {vector <ll> G[N];void add(ll x, ll y) {G[x].push_back(y);}void dfs0(ll now, ll father) {fa[now] = father; sz[now] = 1;for (ll i = 0; i < G[now].size(); i++) {ll x = G[now][i];dfs0(x, now); sz[now] += sz[x];if (sz[x] > sz[son[now]]) son[now] = x;}}void dfs1(ll now, ll father) {dfn[now] = ++dfn[0]; dy[dfn[0]] = now;if (son[now]) {top[son[now]] = top[now]; dfs1(son[now], now);}for (ll i = 0; i < G[now].size(); i++) {ll x = G[now][i]; if (x == son[now]) continue;top[x] = x; dfs1(x, now);}}void build() {dfs0(1, 0); top[1] = 1; dfs1(1, 0);T.build(1, 1, tot);}void update_root(ll now) {while (now) {T.update(1, 1, tot, dfn[top[now]], dfn[now], 1);now = fa[top[now]];}}ll query_root(ll now) {ll re = 0;while (now) {(re += T.query(1, 1, tot, dfn[top[now]], dfn[now])) %= mo;now = fa[top[now]];}return re;}
}P;struct SAM {ll insert(ll x) {ll p = lst, np = ++tot; lst = np;d[np].len = d[p].len + 1;for (; p && !d[p].son[x]; p = d[p].fa) d[p].son[x] = np;if (!p) d[np].fa = 1;else {ll q = d[p].son[x];if (d[q].len == d[p].len + 1) d[np].fa = q;else {ll nq = ++tot; d[nq] = d[q];d[nq].len = d[p].len + 1;d[q].fa = d[np].fa = nq;for (; p && d[p].son[x] == q; p = d[p].fa) d[p].son[x] = nq;}}return np;}void build() {for (ll i = 2; i <= tot; i++) P.add(d[i].fa, i);}
}S;int main() {freopen("string.in", "r", stdin);freopen("string.out", "w", stdout);scanf("%lld", &n);scanf("%s", s + 1);for (ll i = 1; i <= n; i++) pla[i] = S.insert(s[i] - 'a');S.build(); P.build();ll sum = 0, ans = 0;for (ll i = 1; i <= n; i++) {(sum += P.query_root(pla[i])) %= mo;P.update_root(pla[i]);(ans += sum) %= mo;printf("%lld\n", ans);}return 0;
}

相关文章:

【YBT2023寒假Day14 C】字符串题(SAM)(树链剖分)(线段树)

字符串题 题目链接&#xff1a;YBT2023寒假Day14 C 题目大意 对于一个字符串 S 定义 F(S) 是 fail 树上除了 0 点其它点的深度和。 G(S) 是 S 每个子串 S’ 的 F(S’) 之和。 然后一个空串&#xff0c;每次在后面加一个字符&#xff0c;要你维护这个串的 G 值。 思路 考虑…...

Tailwind CSS 在Vue中的使用

什么是Tailwind CSS&#xff1f; Tailwind CSS 是一个功能类优先的 CSS 框架&#xff0c;它集成了诸如 flex, pt-4, text-center 和 rotate-90 这样的的类&#xff0c;支持 hover 和 focus 样式&#xff0c;它们能直接在脚本标记语言中组合起来&#xff0c;构建出任何设计。 …...

三层楼100人办公网络如何规划设计实施(实战案例)

如何设计组网 1.采用防火墙+三层交换机+二层POE交换机+AP的方案 2.三层交换机作为网络的核心,提供网络的配置、划分和各个VLAN间的数据交换,而每个VLAN由二层交换机组建 3.网络主干设备的选型,建议网络主干设备或核心层设备选择具备第3层交换功能的高性能主干交换机。 4…...

Redis:实现全局唯一ID

Redis&#xff1a;实现全局唯一ID一. 概述二. 实现&#xff08;1&#xff09;获取初始时间戳&#xff08;2&#xff09;生成全局ID三. 测试为什么可以实现全局唯一&#xff1f;其他唯一ID策略补充&#xff1a;countDownLatch一. 概述 全局ID生成器&#xff1a;是一种在【分布式…...

webpack打包基本原理——实现webpack打包核心功能

webpack打包的基本原理 核心功能就是把我们写的模块化代码转换成浏览器能够识别运行的代码&#xff0c;话不多说我们一起来了解它 首先我们建一个空项目用 npm init -y 创建一个初始化的&#xff0c;在跟目录下创建src文件夹&#xff0c;src下创建index.js&#xff0c;add.js…...

git的使用(终端输入指令) 上

git目录前言1.创建仓库2.创建文件和修改数据状态分区![分区](https://img-blog.csdnimg.cn/d124dec6b2b14769ad20b75490f29cae.png)3 .删除、撤销重置 、和比较前言 今天带大家手把手敲一遍 git 流程&#xff1a; 安装一下git&#xff08;详细观看我之前发的git文档&#xff0…...

react定义css样式,使用less,css模块化

引入外部 css文件 import ./index.css此时引入的样式是全局样式 使用less 安装 npm i style-loader css-loader sass-loader node-sass -D生成config文件夹 npm run eject配置 以上代码运行完&#xff0c;会在根目录生成config文件夹 进入 config > webpack.config.js 查找…...

基于JavaWeb的学生管理系统

文章目录 项目介绍主要功能截图:登录用户信息管理院系信息管理班级信息管理新增学生课程管理成绩管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系�…...

win11右键新建菜单添加选项

需要操作 2 处注册表&#xff0c; 以下以在右键新建菜单中添加 .html 为例 在主键 HKEY_CLASSES_ROOT 中&#xff0c;搜索 .html 找到后 &#xff0c;右键点击它&#xff0c;选 新建 ->项&#xff0c; 在这里插入图片描述 项目名字是&#xff1a;ShellNew 新建后&#x…...

leetcode Day5(卡线复试,放弃版)

Day5 最后一个单词长度&#xff08;要求最后一个&#xff0c;可以反向计数&#xff09; int lens.length()-1; while(s.charAt(len)){len--;//最后是一个空格&#xff0c;就是无字符时 } int wordlen0;//记录字符长度 /*charAt() 方法用于返回指定索引处的字符。索引范围为从 0…...

cmake 入门二 库的编译,安装与使用

工程描述 &#xff11;&#xff0c;建立一个静态库和动态库&#xff0c;提供HelloFunc 函数供其他程序编程使用&#xff0c;HelloFunc 向终端输出Hello World字符串。 &#xff12;&#xff0c;安装头文件与共享库。 1 库的工程结构 1.1 工程目录下的CMakeLists.txt PROJECT…...

Python中实现将内容进行base64编码与解码

一、需求说明需要使用Python实现将内容转为base64编码&#xff0c;解码&#xff0c;方便后续的数据操作。二、base64简介Base64是一种二进制到文本的编码方式【是一种基于 64 个可打印字符来表示二进制数据的表示方法&#xff08;由于 2^664&#xff0c;所以每 6 个比特为一个单…...

集合TreeSet的使用-java

TreeSet的特点&#xff1a;可排序、不重复、无索引。可排序&#xff1a;按照元素的大小默认升序排序&#xff1b;底层是基于红黑树的数据结构实现排序的&#xff0c;增删改查性能都较好。对于数值、字符串类型的&#xff08;Integer 、Double、String&#xff09;TreeSet可以排…...

Mybatis-plus 分页集成以及基本使用总结 入门和案例 注解连表查询分页案例等

简介 Mybaits-plus 是mybits 的升级版&#xff0c;从mybaits 升级到mybaits-plus 可以实现平滑升级 Mybaits-plus 本身提供了大量的基本查询方法以及强大的 Wrapper(包装) 类 用于查询的 QueryWrapper 以及 更新的 UpdateWrapper &#xff0c;使用Wrapper 基本已经可以构建大…...

5个设计师常用素材库

推荐5个设计素材网站&#xff0c;免费下载&#xff01; 1、菜鸟图库 菜鸟图库-免费设计素材下载 菜鸟图库是一个素材量非常丰富的网站&#xff0c;该网站聚合了平面、UI、淘宝电商、高清背景图、图片、插画等高质量素材。平面设计模板非常多&#xff0c;很多都能免费下载&…...

PHP/7.2.11 缺少 apache2/logs/httpd.pid 文件

启动服务时&#xff1a;systemctl restart httpd.service&#xff0c;报错&#xff1a;● httpd.service - httpd serviceLoaded: loaded (/etc/systemd/system/httpd.service; enabled; vendor preset: disabled)Active: failed (Result: exit-code) since 五 2023-02-24 16:1…...

【centos7下部署mongodb】

一.安装环境 CentOS7MongoDB4.0.13正式版。 二.下载MongoDB 1.1 官网下载地址&#xff1a;https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.13.tgz 1.2 将压缩包通过xftp上传到服务器/opt目录&#xff0c;然后解压、改名 三. 配置环境变量及配置文件 3.1配置系…...

pycharm首次使用爬虫框架scrapy遇到的问题和解决方法(二)

在首次使用scrapy框架的过程中,一直是对着别人的框架步骤撸代码的。然而,撸着撸着发现好像别人的也用不了。后面就只能自己找踏坑了。 问题报错: 1,IndexError: list index out of range 2,pymysql.err.ProgrammingError: (1064, "You have an error in your SQL s…...

pyflink学习笔记(二):table_apisql

Joins Inner Join 官网说明&#xff1a;和 SQL 的 JOIN 子句类似。关联两张表。两张表必须有不同的字段名&#xff0c;并且必须通过 join 算子或者使用 where 或 filter 算子定义至少一个 join 等式连接谓词。先创建2个表&#xff0c;两个表的字段是相同的&#xff0c;我想验证…...

嵌入式 STM32 实现STemwin移植+修改其配置文件,驱动LCD显示文本 (含源码,建议收藏)

目录 一、STemwin 简介 二、源码下载 1、在移植STemwin源码之前&#xff0c;需要一个已经具备LCD读写&#xff0c;填充指定颜色等函数功能的一个工程&#xff1b; 2、STemwin 3、源码下载 三、STemwin移植 1、解压源码路径 2、STemwin文件介绍 四、修改配置文件&…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...