2024牛客(4)K题

news2024/11/15 8:45:47

登录—专业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.coloradmin.cn/o/1463931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习笔记-Git

Git 问题一描述解决方法注意事项 问题一 描述 在commit和push的时候因为网络太慢了中途强行关闭了进程&#xff0c;而push的内容因为文件过大导致无法正常push 按照原本的流程在push的时候会提示失败&#xff0c;并且需要在解决了大文件之后重新push 而因为中途中断了&#x…

GitHubApp大集结!GSYGithubAppFlutter带你飞越编程世界!

GitHubApp大集结&#xff01;GSYGithubAppFlutter带你飞越编程世界&#xff01; GSYGithubAppFlutter是一个功能丰富、跨平台的开源GitHub客户端应用程序&#xff0c;基于Flutter框架开发。该项目属于GSYGithubApp系列&#xff0c;目前已经拥有Flutter、Weex、ReactNative和Ko…

Microsoft PowerToys:自定义 Windows 的实用程序

Microsoft PowerToys&#xff1a;自定义 Windows 的实用程序 Microsoft PowerToys 是一组实用程序&#xff0c;供高级用户调整和简化其 Windows 体验以提高工作效率。 微软官方地址为&#xff1a;https://learn.microsoft.com/en-us/windows/powertoys/&#xff0c;其github源…

防火墙内容安全笔记

目录 DFI和DPI IDS和IPS 签名 AV URL过滤 HTTPS过滤 内容过滤 文件类型过滤 文件内容过滤 邮件过滤 VPN概述 DFI和DPI DFI和DPI技术 --- 深度检测技术 DPI DPI --- 深度包检测技术 --- 主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#…

Spring的copy属性

Spring 的 BeanUtils.copyProperties()实现的是浅拷贝 ClassA public class ClassA {private Integer age;private String name;private ClassC c;public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}public String getName() {return n…

【stm32】hal库-双通道ADC采集

【stm32】hal库-双通道ADC采集 CubeMX图形化配置 程序编写 /* USER CODE BEGIN PV */ #define BATCH_DATA_LEN 1 uint32_t dmaDataBuffer[BATCH_DATA_LEN]; /* USER CODE END PV *//* USER CODE BEGIN 2 */lcd_init();lcd_show_str(10, 10, 24, "Demo14_4:ADC1 ADC2 S…

vue大文件读取部分内容,避免重复加载大文件,造成流量浪费

使用场景&#xff1a;项目点云地图是pcd文件&#xff0c;但是文件可能上百兆&#xff0c;我需要获取到文件中的版本信息&#xff0c;跟本地的缓存文件做比较&#xff0c;如果不一致&#xff0c;才会加载整个文件。从而节省流量。 避免重复加载整个“.pcd文件&#xff0c;以最大…

2.21数据与结构算法学习日记(最小生成树prim算法)

目录 最小生成树prim 最小生成树算法是一种用来在一个加权连通图中找到最小生成树的算法。最小生成树是一个包含图中所有顶点的树&#xff0c;其总权值最小。 prim算法 洛谷题目示例 P3366 【模板】最小生成树 题目描述 输入格式 输出格式 输入输出样例 说明/提示 题…

郑板桥的人生境界是难得糊涂

郑板桥是康熙秀才&#xff0c;雍正举人&#xff0c;乾隆进士。 郑板桥小时候跟父亲在真州读书&#xff0c;长大后在真州教书。后来&#xff0c;郑板桥去扬州卖画谋生。 郑板桥没有老师&#xff0c;画画靠自己琢磨。郑板桥一生画竹&#xff0c;画了四十年的竹子&#xff0c;主…

【析】考虑同时取送和时间窗的车辆路径及求解算法

期刊&#xff1a;computer engineering and applications 计算机工程与应用![c 引言 1. 问题分析 1.1 问题描述 问题描述为&#xff1a; 若干运输车辆从配送中心出发为客户取送货并最终返回配送中心&#xff0c;每位客户仅由一辆车服务一次&#xff0c;车辆在配送过程中任…

《图解设计模式》笔记(二)交给子类

三、Template Method模式&#xff1a;将具体处理交给子类 示例程序类图 public static void main(String[] args) {// 生成一个持有H的CharDisplay类的实例AbstractDisplay d1 new CharDisplay(H);// 生成一个持有"Hello, world."的StringDisplay类的实例AbstractD…

11-树-二叉树的前序遍历

这是树的第11篇算法&#xff0c;力扣链接。 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 做了这么久的树问题&#xff0c;现在开始回忆三种遍历方法&#xff0c;这篇文章…

C#上位机与三菱PLC的通信06--MC协议之QnA-3E报文测试

1、A-3E报文回顾 1、存储区分类及访问规则 2、命令类型 命令由主命令子命令组成 3、报文结构 2、启动mc服务器 3、创建VS项目 这节继续使用上节的VS2022的项目&#xff0c;增加一个方法 MCTestA3E()&#xff0c;具体怎么创建项目&#xff0c;见上节的过程。C#上位机与三菱…

Spring Security学习(六)——配置多个Provider(存在两种认证规则)

前言 《Spring Security学习&#xff08;五&#xff09;——账号密码的存取》一文已经能满足一般应用的情况。但实际商业应用也会存在如下的情况&#xff1a;用户提交的账号密码&#xff0c;能在本地的保存的账号密码匹配上&#xff0c;或者能在远端服务认证中匹配上&#xff…

171基于matlab的随机共振微弱信号检测

基于matlab的随机共振微弱信号检测&#xff0c;随机共振描述了过阻尼布朗粒子受周期性信号和随机噪声的共同作用下,在非线性双稳态系统中所发生的跃迁现象. 随机共振可用于弱信号的检测。程序已调通&#xff0c;可直接运行。

Linux用到的命令

1 压缩文件 tar -czf wonderful.tar.gz pm 这个命令的作用就是创建一个以.tar.gz结尾的包文件&#xff0c;然后调用gzip程序将当前目录下的pm文件夹压缩到这个以.tar.gz结尾的文件里面去

Colmap学习笔记(一):Pixelwise View Selection for Unstructured Multi-View Stereo论文阅读

1. 摘要 本文展示一套MVS系统&#xff0c;该系统利用非结构化的图片实现鲁棒且稠密的建模。本文的主要贡献是深度和法向量的联合估计&#xff0c;用光度和几何先验进行像素筛选&#xff0c;多视图几何一致项&#xff0c;该项同时进行精修和基于图片的深度和法向量的融合。在标…

C2-1.6 Dropout正则化——提高泛化能力

C2-1.6 Dropout正则化——提高泛化能力 1、参考书籍 2、什么是Dropout正则化 以图一为例&#xff1a; 假设在训练图一所示的神经网络&#xff0c;它存在过拟合&#xff08;模型过于复杂情况&#xff09;&#xff0c;dropout 会遍历网络的每一层&#xff08;每一层设置的阈值不…

StarRocks加速查询——低基数全局字典

前言 StarRocks-2.0引入了低基数全局字典&#xff0c;可以通过全局字典将字符串的相关操作转换成整型相关操作&#xff0c;极大提升了查询性能。StarRocks 2.0后的版本默认会开启低基数字典优化。 一、低基数字典 对于利用整型替代字符串进行处理&#xff0c;通常使用字典编码…

Docker之查看并获取最新Ubuntu镜像(十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…