Leetcode 3569. Maximize Count of Distinct Primes After Split

news2025/6/7 2:56:01
  • Leetcode 3569. Maximize Count of Distinct Primes After Split
    • 1. 解题思路
    • 2. 代码实现
  • 题目链接:3569. Maximize Count of Distinct Primes After Split

1. 解题思路

这一题的话思路倒是还好,显然,要找出所有distinct的质数的切分,我们首先就是先将 10 5 10^5 105以内的所有质数找出来,这样,我们就能够快速的找出原始的数组当中的所有的质数的位置了。

然后,我们考察最优的切分方式,注意到:

  • 所有仅出现一次的质数,无论怎么切分,其贡献值都为一;
  • 对于出现过多次的质数,考察其第一次出现的位置与最后一次出现的位置,我们只要在其中间任意位置切一刀,则其贡献值就会由1变成2。

因此,这道题事实上也就变成了,给定若干个区域 [ l i , r i ] [l_i, r_i] [li,ri],找出一个位置 p p p,使之同时存在的区域最多。这个的话我们只需要依次将所有的 [ l i , r i ] [l_i, r_i] [li,ri]上的元素加一,然后考察线段当中的最大值即可。

但是,我们需要频繁地对对元素进行修改以及query,因此我们需要不断地修改整段区间 [ l k , r k ] [l_k, r_k] [lk,rk]上的值,然后再去进行query,这个就是一个标准的Lazy Segment Tree的题目了,虽然我还是不能熟练地写出对应的代码,不过相关的内容网上多的是,deepseek也能很快速地给出对应的代码实现,所以这里就不过多赘述了。

事实上,对应的Lazy Segment Tree的算法实现,我也是直接让deepseek帮我写作完成的……

2. 代码实现

给出python代码实现如下:

def get_primes(n):
    status = [0 for _ in range(n+1)]
    primes = set()
    for i in range(2, n+1):
        if status[i] != 0:
            continue
        primes.add(i)
        for j in range(i, n+1, i):
            status[j] = 1
    return primes

PRIMES = get_primes(10**5)

class LazySegmentTree:
    def __init__(self, arr):
        """
        根据数组 arr 构建惰性线段树
        :param arr: 输入数组
        """
        self.n = len(arr)
        self.arr = arr
        # 初始化线段树和惰性标记数组(4倍原始数组大小)
        self.size = 4 * self.n
        self.tree = [-float('inf')] * self.size  # 存储区间最大值
        self.lazy = [0] * self.size             # 存储惰性标记
        self._build(0, 0, self.n - 1)           # 从根节点开始建树

    def _build(self, node, start, end):
        """
        递归构建线段树
        :param node: 当前节点索引
        :param start: 当前节点表示的区间起始索引
        :param end: 当前节点表示的区间结束索引
        """
        if start == end:
            # 叶子节点,直接存储数组值
            self.tree[node] = self.arr[start]
            return
        
        mid = (start + end) // 2
        left_node = 2 * node + 1  # 左子节点索引
        right_node = 2 * node + 2  # 右子节点索引
        
        # 递归构建左右子树
        self._build(left_node, start, mid)
        self._build(right_node, mid + 1, end)
        
        # 当前节点值为左右子树的最大值
        self.tree[node] = max(self.tree[left_node], self.tree[right_node])

    def _push_down(self, node, start, end):
        """
        下推惰性标记到子节点
        :param node: 当前节点索引
        :param start: 当前节点表示的区间起始索引
        :param end: 当前节点表示的区间结束索引
        """
        if self.lazy[node] != 0:
            # 更新当前节点的值
            self.tree[node] += self.lazy[node]
            
            if start != end:  # 非叶子节点,标记下推
                left_node = 2 * node + 1
                right_node = 2 * node + 2
                # 将惰性标记添加到子节点
                self.lazy[left_node] += self.lazy[node]
                self.lazy[right_node] += self.lazy[node]
            
            # 清除当前节点的惰性标记
            self.lazy[node] = 0

    def update(self, l, r, val):
        """
        将闭区间 [l, r] 内的所有元素增加 val
        :param l: 区间左边界
        :param r: 区间右边界
        :param val: 要增加的值
        """
        self._update(0, 0, self.n - 1, l, r, val)

    def _update(self, node, start, end, l, r, val):
        """
        递归执行区间更新
        :param node: 当前节点索引
        :param start: 当前节点表示的区间起始索引
        :param end: 当前节点表示的区间结束索引
        :param l: 更新区间左边界
        :param r: 更新区间右边界
        :param val: 要增加的值
        """
        # 先下推当前节点的惰性标记
        self._push_down(node, start, end)
        
        # 当前节点区间与更新区间无交集
        if start > r or end < l:
            return
        
        # 当前节点区间完全包含在更新区间内
        if l <= start and end <= r:
            # 更新当前节点值
            self.tree[node] += val
            if start != end:  # 非叶子节点,更新子节点惰性标记
                left_node = 2 * node + 1
                right_node = 2 * node + 2
                self.lazy[left_node] += val
                self.lazy[right_node] += val
            return
        
        # 部分重叠,递归更新子区间
        mid = (start + end) // 2
        left_node = 2 * node + 1
        right_node = 2 * node + 2
        
        self._update(left_node, start, mid, l, r, val)
        self._update(right_node, mid + 1, end, l, r, val)
        
        # 更新当前节点值为左右子树的最大值
        self.tree[node] = max(self.tree[left_node], self.tree[right_node])

    def query(self, l, r):
        """
        查询闭区间 [l, r] 内的最大元素值
        :param l: 查询区间左边界
        :param r: 查询区间右边界
        :return: 区间内的最大值
        """
        return self._query(0, 0, self.n - 1, l, r)

    def _query(self, node, start, end, l, r):
        """
        递归执行区间查询
        :param node: 当前节点索引
        :param start: 当前节点表示的区间起始索引
        :param end: 当前节点表示的区间结束索引
        :param l: 查询区间左边界
        :param r: 查询区间右边界
        :return: 区间内的最大值
        """
        # 先下推当前节点的惰性标记
        self._push_down(node, start, end)
        
        # 当前节点区间与查询区间无交集
        if start > r or end < l:
            return -float('inf')
        
        # 当前节点区间完全包含在查询区间内
        if l <= start and end <= r:
            return self.tree[node]
        
        # 部分重叠,递归查询子区间
        mid = (start + end) // 2
        left_node = 2 * node + 1
        right_node = 2 * node + 2
        
        left_max = self._query(left_node, start, mid, l, r)
        right_max = self._query(right_node, mid + 1, end, l, r)
        
        return max(left_max, right_max)


class Solution:
    def maximumCount(self, nums: List[int], queries: List[List[int]]) -> List[int]:
        primes_locs = defaultdict(list)
        for i, x in enumerate(nums):
            if x in PRIMES:
                primes_locs[x].append(i)

        n = len(nums)
        segment_tree = LazySegmentTree([0 for _ in range(n)])
        for p, locs in primes_locs.items():
            if len(locs) > 1:
                segment_tree.update(locs[0], locs[-1], 1)

        def query(idx, val):
            nonlocal primes_locs, segment_tree, nums
            old_val = nums[idx]
            nums[idx] = val
            if old_val == val:
                return len(primes_locs) + segment_tree.query(0, n-1)
            if old_val in PRIMES:
                l, r = primes_locs[old_val][0], primes_locs[old_val][-1]
                primes_locs[old_val].pop(bisect.bisect_left(primes_locs[old_val], idx))
                if l == r:
                    primes_locs.pop(old_val)
                    pass
                elif len(primes_locs[old_val]) == 1:
                    segment_tree.update(l, r, -1)
                elif l == idx:
                    new_l = primes_locs[old_val][0]
                    segment_tree.update(idx, new_l-1, -1)
                elif r == idx:
                    new_r = primes_locs[old_val][-1]
                    segment_tree.update(new_r+1, idx, -1)
            if val in PRIMES:
                if val not in primes_locs:
                    primes_locs[val] = [idx]
                else:
                    l, r = primes_locs[val][0], primes_locs[val][-1]
                    bisect.insort(primes_locs[val], idx)
                    if len(primes_locs[val]) == 2:
                        l, r = primes_locs[val][0], primes_locs[val][-1]
                        segment_tree.update(l, r, 1)
                    elif idx < l:
                        segment_tree.update(idx, l-1, 1)
                    elif idx > r:
                        segment_tree.update(r+1, idx, 1)
            return len(primes_locs) + segment_tree.query(0, n-1)

        return [query(idx, val) for idx, val in queries]

提交代码评测得到:耗时7026ms,占用内存46.94MB。

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

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

相关文章

用好 ImageFX,解锁游戏素材生成新姿势:从入门到进阶

用好 ImageFX&#xff0c;解锁游戏素材生成新姿势&#xff1a;从入门到进阶 (备注)大陆ip无法访问到imagefx 地址:https://labs.google/fx/zh/tools/image-fx 对于独立游戏开发者和小型团队而言&#xff0c;美术资源往往是项目推进中的一大痛点。预算有限、专业美术人员缺乏…

01-Redis介绍与安装

01-Redis介绍与安装 SQL与NoSQL SQLNoSQL数据结构结构化非结构化数据关联关联的非关联的查询方式SQL查询非SQL事务特性ACIDBASE存储方式磁盘内存拓展性垂直水平使用场景1、数据结构固定2、相关业务对数据安全性、一致性要求较高1、数据结构不固定2、对安全性、一致性要求不高…

VR博物馆推动现代数字化科技博物馆

VR博物馆&#xff1a;推动现代数字化科博馆新篇章 随着科技的飞速发展&#xff0c;虚拟现实&#xff08;Virtual Reality, VR&#xff09;技术已经逐渐渗透到我们生活的方方面面&#xff0c;其中&#xff0c;VR博物馆作为现代数字化科博馆的重要形式之一&#xff0c;以独特的优…

Python爬虫之数据提取

本章节主要会去学习在爬虫中的如何去解析数据的方法&#xff0c;要学习的内容有&#xff1a; 响应数据的分类结构化数据如何提取非结构化数据如何提取正则表达式的语法以及使用jsonpath解析嵌套层次比较复杂的json数据XPath语法在Python代码中借助lxml模块使用XPath语法提取非…

第2讲、Odoo深度介绍:开源ERP的领先者

一、Odoo深度介绍&#xff1a;开源ERP的领先者 Odoo&#xff0c;其前身为OpenERP&#xff0c;是一款在全球范围内广受欢迎的开源企业管理软件套件。它不仅仅是一个ERP系统&#xff0c;更是一个集成了客户关系管理&#xff08;CRM&#xff09;、电子商务、网站构建、项目管理、…

【TCP/IP和OSI模型以及区别——理论汇总】

参考小林code和卡尔哥&#xff0c;感恩&#xff01; 网络基础篇 面试官您好&#xff01;OSI和TCP/IP是网络通信中两个关键模型&#xff0c;本质都是分层处理数据传输&#xff0c;但设计理念和应用场景差异很大。 OSI模型是理论上的七层架构&#xff0c;从下到上依次是物理层…

STM32 I2C通信外设

1、外设简介 可变多主机 7位/10位寻址 10位寻址&#xff1a;起始之后的两个字节都作为寻址&#xff0c;第一个字节前5位是11110作为10位寻址的标志位 SMBus&#xff1a;系统管理总线&#xff0c;主要用于电源管理&#xff0c;与I2C类似 2、外设结构框图 比较器、自身地址寄…

13. springCloud AlibabaSeata处理分布式事务

目录 一、分布式事务面试题 1.多个数据库之间如何处理分布式事务&#xff1f; 2.若拿出如下场景&#xff0c;阁下将如何应对? 3.阿里巴巴的Seata-AT模式如何做到对业务的无侵入? 4.对于分布式事务问题&#xff0c;你知道的解决方案有哪些?请你谈谈? 二、分布式事务问题…

MySQL 表的内连和外连

一、内连接 内连接实际上就是利用 where 子句对两种表形成的笛卡儿积进行筛选&#xff0c;前面学习的查询都是内连接&#xff0c;也是在开发过程中使用的最多的连接查询。 select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件; 注意&#xff1a;前面学习的都是内连…

VR线上展厅特点分析与优势

VR线上展厅&#xff1a;特点、优势与实际应用 VR线上展厅&#xff0c;作为虚拟现实&#xff08;VR&#xff09;技术在展示行业的创新应用&#xff0c;正逐步改变着传统的展览方式。通过模拟真实的物理环境&#xff0c;为参观者提供身临其境的展览体验&#xff0c;成为展示行业…

Python基于SVM技术的手写数字识别问题项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在当今数字化转型加速的时代&#xff0c;手写数字识别作为图像处理与机器学习领域的一个经典问题&#xff0c;具有广…

2024年数维杯国际大学生数学建模挑战赛A题飞行器激光测速中的频率估计问题解题全过程论文及程序

2024年数维杯国际大学生数学建模挑战赛 A题 复合直升机的建模与优化控制问题 原题再现&#xff1a; &#xff08;一&#xff09; 问题的背景   空速&#xff0c;即飞机相对于空气的速度&#xff0c;是飞行期间需要监控的关键参数。空速与飞行状态密切相关&#xff0c;如迎角…

DeepSeek+SpringAI实现流式对话

大模型的响应速度通常是很慢的&#xff0c;为了避免用户用户能够耐心等待输出的结果&#xff0c;我们通常会使用流式输出一点点将结果输出给用户。 那么问题来了&#xff0c;想要实现流式结果输出&#xff0c;后端和前端要如何配合&#xff1f;后端要使用什么技术实现流式输出呢…

【Spark征服之路-2.1-安装部署Spark(一)】

实验目标&#xff1a; 本节课实验将完成Spark 4种部署模式的其中2种&#xff0c;分别是Local、Standalone模式。 实验准备工作&#xff1a; 三台linux虚拟机spark的压缩包 实验步骤&#xff1a; Spark-local Spark的Local模式仅需要单个虚拟机节点即可&#xff0c;无需启…

VS代码生成工具ReSharper v2025.1——支持.NET 10和C# 14预览功能

实质上&#xff0c;ReSharper特征可用于C#&#xff0c;VB.net&#xff0c;XML&#xff0c;Asp.net&#xff0c;XAML和构建脚本。 使用ReSharper&#xff0c;你可以进行深度代码分析&#xff0c;智能代码协助&#xff0c;实时错误代码高亮显示&#xff0c;解决方案范围内代码分析…

【Godot】如何导出 Release 版本的安卓项目

在使用 Godot 引擎开发安卓游戏或应用时&#xff0c;发布到应用市场&#xff08;如 Google Play、华为应用市场等&#xff09;通常需要生成一个 Release 版本的 .apk 包&#xff0c;而非 Debug 版本。本文将详细介绍如何将 Godot 项目导出为 Release 版本的安卓项目&#xff0c…

VSCode 工作区配置文件通用模板(CMake + Ninja + MinGW/GCC 编译器 的 C++ 或 Qt 项目)

下面是一个通用模板&#xff0c;适用于大多数使用 VSCode CMake Ninja MinGW/GCC 编译器 的 C 或 Qt 项目。你可以将这个 .vscode 文件夹复制到你的项目根目录下&#xff0c;稍作路径调整即可使用。 &#x1f4c1; .vscode/ 目录结构&#xff08;通用模板&#xff09; .vs…

Java八股文——Redis篇

目录 1. 缓存穿透解决方案1. 缓存空值2. 布隆过滤器&#xff08;Bloom Filter&#xff09;3. 参数校验4. 接口限流与验证码 2. 缓存击穿解决方案1. 设置热点数据永不过期&#xff08;或很长过期时间&#xff09;2. 使用互斥锁&#xff08;如分布式锁&#xff09;3. 利用异步更新…

爬虫接口类型判断与表单需求识别全解析

爬虫接口类型判断与表单需求识别全解析 在爬虫开发中&#xff0c;准确判断目标接口的类型以及是否需要表单提交&#xff0c;是实现高效、稳定爬取的关键一步。本文将通过实际案例&#xff0c;详细介绍如何通过浏览器开发者工具和代码验证来判断接口类型及表单需求。 一、接口…

Chainlink:连接 Web2 与 Web3 的去中心化桥梁

区块链技术通过智能合约实现了去中心化的自动执行&#xff0c;但智能合约无法直接访问链下数据&#xff0c;限制了其在现实世界的应用。Chainlink 作为去中心化预言机网络&#xff0c;以信任最小化的方式解决了这一问题&#xff0c;成为连接传统互联网&#xff08;Web2&#xf…