2024牛客(4)K题

登录—专业IT笔试面试备考平台_牛客网

using i64 = long long;
using ll = long long;
constexpr ll M = 1e9 + 7;
template<class Info>
struct SegmentTree {int n;std::vector<Info> info;SegmentTree() : n(0) {}SegmentTree(int n_, Info v_ = Info()) {init(n_, v_);}template<class T>SegmentTree(std::vector<T> init_) {init(init_);}void init(int n_, Info v_ = Info()) {init(std::vector<Info>(n_, v_));}template<class T>void init(std::vector<T> init_) {n = init_.size();info.assign(4 << (int)std::log2(n), Info());std::function<void(int, int, int)> build = [&](int p, int l, int r) {if (r - l == 1) {info[p] = init_[l];return;}int m = (l + r) / 2;build(2 * p, l, m);build(2 * p + 1, m, r);pull(p);};build(1, 0, n);}void pull(int p) {info[p] = info[2 * p] + info[2 * p + 1];}void modify(int p, int l, int r, int x, const Info& v) {if (r - l == 1) {info[p] = v;return;}int m = (l + r) / 2;if (x < m) {modify(2 * p, l, m, x, v);}else {modify(2 * p + 1, m, r, x, v);}pull(p);}void modify(int p, const Info& v) {modify(1, 0, n, p, v);}Info rangeQuery(int p, int l, int r, int x, int y) {if (l >= y || r <= x) {return Info();}if (l >= x && r <= y) {return info[p];}int m = (l + r) / 2;return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);}Info rangeQuery(int l, int r) {return rangeQuery(1, 0, n, l, r);}template<class F>int findFirst(int p, int l, int r, int x, int y, F pred) {if (l >= y || r <= x || !pred(info[p])) {return -1;}if (r - l == 1) {return l;}int m = (l + r) / 2;int res = findFirst(2 * p, l, m, x, y, pred);if (res == -1) {res = findFirst(2 * p + 1, m, r, x, y, pred);}return res;}template<class F>int findFirst(int l, int r, F pred) {return findFirst(1, 0, n, l, r, pred);}template<class F>int findLast(int p, int l, int r, int x, int y, F pred) {if (l >= y || r <= x || !pred(info[p])) {return -1;}if (r - l == 1) {return l;}int m = (l + r) / 2;int res = findLast(2 * p + 1, m, r, x, y, pred);if (res == -1) {res = findLast(2 * p, l, m, x, y, pred);}return res;}template<class F>int findLast(int l, int r, F pred) {return findLast(1, 0, n, l, r, pred);}
};struct Info {ll a;//表示黄色砖块,当前ll b;ll c = 1;ll d;
};Info operator+(const Info& b, const Info& a) {//b.a + a.a * b.c//b.b + a.a * b.d + a.b //a.c * b.c//a.c * b.d + a.d return { (b.a + ((a.a%M) * (b.c%M))%M)%M, (b.b + ((a.a%M) * (b.d%M)) + a.b)%M, ((a.c%M) * (b.c%M))%M, (((a.c%M) * (b.d%M)%M) + a.d)%M };
}Info Y{ 0, 0, 1, 1 };
Info B{ 1, 0, 0, 1 };//箭头指向下一个位置
Info R{ 0, 0, 2, 1 };//总数量乘以2在加上一个红色砖块int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, q;std::cin >> n >> q;std::string s;std::cin >> s;//最底层的n个区间,比如[0,1)表示第一个区间,代表第一块砖SegmentTree<Info> seg(n);for (int i = 0; i < n; i++) {seg.modify(i, (s[i] == 'Y') ? Y : ((s[i] == 'B') ? B : R));/*for (int j = 0; j < n; j++) {Info t = seg.rangeQuery(j, j + 1);std::cout <<j<<":"<< t.a << ' ' << t.b << ' ' << t.c << ' ' << t.d << '\n';}*/}while (q--) {int o;std::cin >> o;if (o == 1) {int p;char c;std::cin >> p >> c;p--;seg.modify(p, (c == 'Y') ? Y : ((c == 'B') ? B : R));}else {int l, r;std::cin >> l >> r;l--;Info res = seg.rangeQuery(l, r);//b和d的和为总数ll ans = (res.b + res.d) % M;std::cout << ans << "\n";}}return 0;
}

第一点:std::vector<Info> info;存的是按区间字符操作后的效果,有点难理解,举个例子,如果你查询[0,1)这个区间相当于查询按第一个字符进行游戏后的效果,如果第一个字符是Y,那么查询的结果就是Info Y{ 0, 0, 1, 1 };至于Info为什么要这么定义我们来看看下面的内容.

其中最难理解的就是下面这一部分

struct Info {ll a;//最左边的柱子的倍数ll b;//所有累计的方块ll c = 1;//现有倍数ll d;//现有这一列的方块
};Info operator+(const Info& b, const Info& a) {//b.a + a.a * b.c//b.b + a.a * b.d + a.b//a.c * b.c//a.c * b.d + a.d return { (b.a + ((a.a%M) * (b.c%M))%M)%M, (b.b + ((a.a%M) * (b.d%M)) + a.b)%M, ((a.c%M) * (b.c%M))%M, (((a.c%M) * (b.d%M)%M) + a.d)%M };
}Info Y{ 0, 0, 1, 1 };
Info B{ 1, 0, 0, 1 };//箭头指向下一个位置
Info R{ 0, 0, 2, 1 };//总数量乘以2在加上一个红色砖块

首先a,b,c,d的意思我都标出来了,为什么要这么定义呢,我们这样想,当中间有很多个操作B出现的时候,那么这个区间是不是有很多个柱子,这样不清楚,让我来画个图

如果产生了多个柱子是不是说明有操作B,第一个柱子不管是YRRY或是什么其它的操作它都不可能产生第二个柱子.假如我们要合并两个区间,

每根柱子表示的无非就是YR的组合,可能是YYYY,RRRR又或者是YRRY等等,不存在B所以最后一根和第一根合并的序列一定是一根,那么效果是怎样的呢, 显然最后一根总方块数我们可以设为k,那么合并后可以表示为((k+a1)*2+a2)*2+a3,原先第一根的方块数为(a1*2+a2)*2+a3,两者的差值不就是把k提到外面来吗及(a1*2+a2)*2+a3+4*k(注意,我只是举了一个只有两个R情况下的例子,*2的数量要根据R的数量来定),那么+重载为什么这样运算也很明显了.

对于第一个算式b.a + a.a * b.c,再使用B之前,第一根的方块数量和R的数量是不确定的,如果第一个区间有B,那么第一个区间的c变量是0,也就是说两个区间合并后的第一根倍数就是b.a,如果第一个区间没有B,说明第二个区间的第一根和第一个区间合并后会变成一根,即b.c不为0而b.a为0,合并后的第一根是a.a乘以b.c.

感觉解释的不是很清楚(*/ω\*),换个解释方法,Info Y{ 0, 0, 1, 1 };第一个1表示当前倍数为自己身的一倍,也就是不翻倍,第二个1表示添加到目前这根柱子里添加一个方块,Info R{ 0, 0, 2, 1 };翻倍后添加,Info B{ 1, 0, 0, 1 };这涉及到好几个运算,首先看最简单的a.c*b.c表示第一根柱子已经固定了,根据之前讲的最后一根和第一根合并的运算,我们要把当前倍数转移到a变量里,及a.a * b.c,因为b是左边的区间,所以按照这个运算,如果它在之前有过B字符,那么它也不为0,所以要加上b.a.

列举了两个,其它的是一样的,就像是自动机一样,涉及到有B和没B的情况,比较难解释,当涉及B的时候某些变量会自动变为0从而做出变换.

b.a(有B/没B) + a.a(有B/没B) * b.c(没B/有B)
b.b(有B/没B) + a.a(有B/没B) * b.d + a.b(有B/没B)         有Ba.a会把b.d添加到非当前柱子
a.c * b.c(没B/有B)
a.c(没B/有B) * b.d + a.d        没有B的时候a.c会把b.d添加到当前柱子 

大概就是这样,尽力了,很难解释.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/484798.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

堆的结构实现与应用

目录 前言: 1.认识堆 a.如何认识堆&#xff1f; b.大根堆与小根堆 c.堆应用的简单认识 2.堆的结构与要实现的功能 3.向上调整算法 4.向下调整算法 5.向堆插入数据并建堆 6.堆的大小 7.堆的判空 8.取堆顶数据 9.删除堆顶数据 10.向上调整时间复杂度 11.向下调整时…

流式存储音频/视频

目录 流式存储音频/视频 1.1 具有元文件的万维网服务器 1.2 媒体服务器 1.3 实时流式协议 RTSP 使用 RTSP 的媒体服务器的工作过程 流式存储音频/视频 “存储”音频/视频文件不是实时产生的&#xff0c;而是已经录制好的&#xff0c;通常存储在光盘或硬盘中。 传统浏览器…

初始php及其变量与常量

华子目录 什么是phpphp发展史平台支持和数据库支持网站静态网站和动态网站的区别静态网站动态网站的特点 关键名词解析服务器概念IP的概念域名DNS端口 web程序的访问流程静态网站访问流程动态网站访问流程 php标记脚本标记标准标记&#xff08;常用&#xff09; php注释php语句…

having子句

目录 having子句 having和where的区别 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 现在要求查询出每个职位的名称&#xff0c;职位的平均工资&#xff0c;但是要求显示平均工资高于 200 的职位 按照职位先进行分组&#xff0c;同…

[职场] Android是什么?Android行业有哪些- #媒体#经验分享

Android是什么&#xff1f;Android行业有哪些? Android是一个由Google开发的移动操作系统&#xff0c;它被广泛应用于智能手机、平板电脑、智能手表、智能电视等移动设备上。Android系统基于Linux内核&#xff0c;提供了丰富的应用程序框架、用户界面、多媒体支持、网络功能等…

补环境框架过某物

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018…

Linux之用户和用户组的深入了解

目录 一、简介 1.1、用户&#xff1a; 1.2、用户组 1.3、UID和GID 1.3、用户账户分类 查看用户类别 超级用户root(0) 程序用户(1~499) 普通用户(500~65535) 二、用户 2.1、添加新的用户账号&#xff1a;useradd 2.2、删除账号&#xff1a;userdel 有-r与没有-r区别…

petalinux_zynq7 驱动DAC以及ADC模块之四:python实现http_api

前文&#xff1a; petalinux_zynq7 C语言驱动DAC以及ADC模块之一&#xff1a;建立IPhttps://blog.csdn.net/qq_27158179/article/details/136234296petalinux_zynq7 C语言驱动DAC以及ADC模块之二&#xff1a;petalinuxhttps://blog.csdn.net/qq_27158179/article/details/1362…

Java并发基础:原子类之AtomicBoolean全面解析

本文概要 AtomicBoolean类优点在于能够确保布尔值在多线程环境下的原子性操作&#xff0c;避免了繁琐的同步措施&#xff0c;它提供了高效的非阻塞算法实现&#xff0c;可以大大提成程序的并发性能&#xff0c;AtomicBoolean的API设计非常简单易用。 AtomicBoolean核心概念 …

运维07:堡垒机

什么是跳板机 跳板机就是一台服务器而已&#xff0c;运维人员在使用管理服务器的时候&#xff0c;必须先连接上跳板机&#xff0c;然后才能去操控内网中的服务器&#xff0c;才能登录到目标设备上进行维护和操作 开发小张 ---> 登录跳板机 ---> 再登录开发服务器 测试…

十四、图像几何形状绘制

项目功能实现&#xff1a;矩形、圆形、椭圆等几何形状绘制&#xff0c;并与原图进行相应比例融合 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 drawing.h #pragma once#include<opencv2/opencv.hpp>using namespace cv;class DRAWING { public:void…

解决Jenkins-2.396启动报错:Failed to start Jenkins Continuous Integration Server.

场景&#xff1a;现有环境已经使用Java 8在运行业务&#xff0c;安装Jenkins后启动报错。 原因&#xff1a;因为Jenkins-2.396 依赖于Java 11 版本才能启动。 解决方法&#xff1a; yum 安装Java11 yum install java-11-openjdk-devel java-11-openjdk 或者二进制安装java11修…