2438. 二的幂数组中查询范围内的乘积

初始理解题目

首先,我们需要清楚地理解题目在说什么。题目给出一个正整数 n,要求我们构造一个数组 powers,这个数组满足以下条件:

  1. 元素性质​:数组中的每个元素都是 2 的幂。即,每个元素可以表示为 2^k,其中 k 是非负整数(k ≥ 0)。
  2. 和的条件​:这些 2 的幂的和等于给定的 n

  3. 最少数目​:在所有满足上述条件的数组中,powers应该包含最少数量的元素。

  4. 非递减顺序​:数组中的元素是按非递减顺序排列的,即对于任意 i < j,有 powers[i] ≤ powers[j]
  5. 唯一性​:在满足上述所有条件的情况下,构造 powers的方法是唯一的。

任何正整数 n都可以表示为若干个不同的2的幂的和,这实际上就是 n的二进制表示。例如:

5 的二进制是 101,可以表示为 4+1=5。

6 的二进制是 110,可以表示为 4+2=6。

7 的二进制是 111,可以表示为 4+2+1=7

在这种表示中,每个2的幂最多出现一次,因为二进制每一位只能是0或1。这种表示方法已经使用了最少数量的2的幂(因为不能合并相同的幂次)。

然而,题目允许数组中的元素可以重复(因为是非递减顺序,可以连续相同),但要求最少数目。这意味着我们需要尽可能合并相同的2的幂。

我们需要解决两个主要部分:

在前面的讨论中,我们已经明确了 powers的构造方法:将 n的二进制表示中所有为 1的位对应的2的幂按从小到大的顺序排列。例如:

构造 powers数组​:给定一个正整数 n,构造一个由2的幂组成的、非递减的数组 powers,使得 powers中所有元素的和为 n,并且 powers中的元素数量尽可能少。这个数组是唯一的。

处理查询 queries​:给定多个查询 queries[i] = [lefti, righti],对于每个查询,我们需要计算 powers数组中从索引 lefti到 righti(包含两端)的所有元素的乘积,并将结果取余。

例如:

  • powers = [1, 4],查询 [0, 1]→ 计算 1 * 4 = 4
  • powers = [2, 4],查询 [0, 0]→ 计算 2

解决思路

构造 powers数组​:

  • 将 n转换为二进制遍历二进制的每一位,如果该位为 1,则将对应的2的幂加入 powers
  • 由于二进制是从低位到高位读取的,而 powers需要是非递减的,因此直接按从小到大的顺序添加即可。

预处理 powers的前缀积​:

  • 为了高效计算任意区间 [left, right]的乘积,可以预先计算 powers的前缀积数组 prefix。
  • prefix[0] = powers[0]
  • prefix[i] = prefix[i-1] * powers[i] % MOD(其中 MOD = 10^9 + 7)
  • 这样,区间 [left, right]的乘积可以表示为 prefix[right] / prefix[left-1](如果 left > 0),或者 prefix[right](如果 left == 0)。
  • 由于模运算中除法等同于乘以逆元,因此需要预先计算 prefix的逆元组 inv_prefix。

处理查询​:    

  • 对于每个查询 [left, right]:
  • 如果 left == 0,则结果为 prefix[right]。
  • 否则,结果为 prefix[right] * inv_prefix[left-1] % MOD。
  • 由于 prefix和 inv_prefix已经预先计算,每个查询可以在 O(1) 时间内完成
具体步骤
1.​构造 powers数组​:

初始化 powers = []。

        power = 1(即 2的0次方)。

当 n > 0:

        如果 n % 2 == 1,将 power加入 powers。

        n = n // 2。

        power = power * 2。

        这样得到的 powers已经是非递减顺序。

2.计算前缀积 prefix​:

初始化 prefix = [1] * len(powers)。

prefix[0] = powers[0] % MOD。

对于 i从 1到 len(powers)-1:

prefix[i] = (prefix[i-1] * powers[i]) % MOD。

3.计算逆元前缀积 inv_prefix​:

逆元的计算可以通过费马小定理:inv(a) = pow(a, MOD-2, MOD)。

初始化 inv_prefix = [1] * len(powers)。

inv_prefix[-1] = pow(prefix[-1], MOD-2, MOD)。

对于 i从 len(powers)-2到 0:

inv_prefix[i] = (inv_prefix[i+1] * powers[i+1]) % MOD。

4.处理查询​:

对于每个查询 [left, right]:

        如果 left == 0:

                answer = prefix[right]。

        否则:

                answer = (prefix[right] * inv_prefix[left-1]) % MOD。

                将 answer加入 answers。

示例验证

示例1​:

  • n = 5→ powers = [1, 4]

  • prefix = [1, 4](因为 1 % MOD = 11 * 4 % MOD = 4)。

  • inv_prefix

    • inv_prefix[1] = pow(4, MOD-2, MOD)

    • inv_prefix[0] = (inv_prefix[1] * 4) % MOD

    假设 MOD = 10^9 + 7

    • pow(4, MOD-2, MOD)是 4的逆元,即 x满足 4 * x ≡ 1 mod MOD

    • 计算得 inv_4 = 250000002(因为 4 * 250000002 = 1000000008 ≡ 1 mod 1000000007)。

    • inv_prefix[1] = 250000002

    • inv_prefix[0] = (250000002 * 4) % MOD = 1

  • 查询 [0, 1]

    • left = 0→ answer = prefix[1] = 4

  • 查询 [1, 1]

    • left = 1→ answer = prefix[1] * inv_prefix[0] % MOD = 4 * 1 % MOD = 4

示例2​:

  • n = 6→ powers = [2, 4]

  • prefix = [2, 8]

  • inv_prefix

    • inv_prefix[1] = pow(8, MOD-2, MOD)

      • inv_8 = 125000001(因为 8 * 125000001 = 1000000008 ≡ 1 mod 1000000007)。

    • inv_prefix[0] = (125000001 * 4) % MOD = 500000004(因为 125000001 * 4 = 500000004)。

  • 查询 [0, 1]

    • left = 0→ answer = prefix[1] = 8

  • 查询 [0, 0]

    • left = 0→ answer = prefix[0] = 2

边界情况

  1. 1.

    n = 0​:

    • 题目中 n是正整数,不考虑。

  2. 2.

    n = 1​:

    • powers = [1]

    • prefix = [1]

    • 查询 [0, 0]→ 1

  3. 3.

    查询的 left或 right超出 powers的索引范围​:

    • 题目中 queries是基于 powers的索引,假设输入是合法的。

  4. 4.

    powers长度为1​:

    • 所有查询的 left和 right必须为 0

代码实现

 

python

下载

复制

运行

MOD = 10**9 + 7def min_powers(n):powers = []power = 1while n > 0:if n % 2 == 1:powers.append(power)n = n // 2power = power * 2return powersdef solve(n, queries):powers = min_powers(n)m = len(powers)if m == 0:return [0] * len(queries)# Compute prefix productsprefix = [1] * mprefix[0] = powers[0] % MODfor i in range(1, m):prefix[i] = (prefix[i-1] * powers[i]) % MOD# Compute inverse prefix productsinv_prefix = [1] * minv_prefix[-1] = pow(prefix[-1], MOD-2, MOD)for i in range(m-2, -1, -1):inv_prefix[i] = (inv_prefix[i+1] * powers[i+1]) % MOD# Process queriesanswers = []for left, right in queries:if left == 0:res = prefix[right]else:res = (prefix[right] * inv_prefix[left-1]) % MODanswers.append(res)return answers

复杂度分析

  1. 1.

    构造 powers​:

    • 时间:O(log n),因为每次 n除以2。

    • 空间:O(log n),存储 powers

  2. 2.

    计算前缀积和逆元前缀积​:

    • 时间:O(m),其中 m是 powers的长度(最多 log n)。

    • 空间:O(m),存储 prefix和 inv_prefix

  3. 3.

    处理查询​:

    • 每个查询 O(1),总时间 O(q),其中 q是查询数量。

    • 空间:O(q),存储结果。

总时间复杂度:O(log n + q)。

总空间复杂度:O(log n + q)。

优化

注意到 inv_prefix的计算可以优化:

  • inv_prefix[i] = pow(prefix[i], MOD-2, MOD)

  • 这样可以直接计算每个 prefix[i]的逆元,而不需要递推。

  • 但递推的方法在模运算中更高效,因为 pow(a, MOD-2, MOD)的时间是 O(log MOD) ≈ 30 次运算。

示例运行

输入​:

  • n = 5queries = [[0, 1], [1, 1]]

步骤​:

  1. 1.

    powers = [1, 4]

  2. 2.

    prefix = [1, 4]

  3. 3.

    inv_prefix

    • inv_prefix[1] = pow(4, MOD-2, MOD) = 250000002

    • inv_prefix[0] = (250000002 * 4) % MOD = 1

  4. 4.

    查询:

    • [0, 1]prefix[1] = 4

    • [1, 1]prefix[1] * inv_prefix[0] % MOD = 4 * 1 % MOD = 4

输出​:

[4, 4]

最终答案

对于给定的 n和 queries,按照上述方法构造 powers数组,并预处理前缀积和逆元前缀积,然后对每个查询计算区间乘积并取余,最后返回所有查询的结果。

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

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

相关文章

【PyTorch学习笔记 - 01】 Tensors(张量)

最近项目需要优化一下目标检测网络&#xff0c;在这个过程中发现还是得增加对框架底层的掌握才可行。于是准备对pytorch的一些基本概念做一些再理解。参考PyTorch的wiki&#xff0c;对自己的学习过程做个记录。 Tensors 是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似…

【C/C++】(struct test*)0->b 讲解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、什么是结构体成员的偏移量&#xff1f; 二、为什么需要计算偏移量&#xff1f; 三、如何计算偏移量&#xff1f; 四、总结 一、什么是结构体成员的偏移量&#…

使用Pytest进行接口自动化测试(三)

&#xff08;一&#xff09;YAML 之前在项目中&#xff0c;我们也是用过YAML来做配置文件&#xff0c;他用于以人类可读的形式存储信息&#xff0c; 特点: 一种简易的可读语言&#xff0c;用于人和计算机交换数据 通常用来存储配置信息 跟python类似&…

算法训练营day46 647. 回文子串、516.最长回文子序列、动态规划总结篇

今天是动态规划的最后一篇内容了&#xff0c;本篇主要是针对回文字符串这种“与众不同”的递推规律来进行讲解 647. 回文子串 统计并返回这个字符串中 回文子串 的数目 暴力解法 两层for循环&#xff0c;遍历区间起始位置和终止位置&#xff0c;然后还需要一层遍历判断这个区…

Qt界面优化

1.QSS在网页前端开发领域中&#xff0c;CSS 是一个至关重要的部分&#xff0c;描述了一个网页的 “样式”&#xff0c;从而起到对网页美化的作用。所谓样式&#xff0c;包括不限于大小、位置、颜色、背景、间距、字体等等。网页开发作为 GUI 的典型代表&#xff0c;也对于其他客…

week1+2+3

408 计组 1.基本组成2.数据的表示和运算定点数&#xff1a;把数字分为定点整数和定点小数分开存储 浮点数&#xff1a;用科学计数法存储 原码 -全部取反-> 反码 反码 1->补码 补码 -符号位取反->移码带余除法&#xff1a;设x,m∈Z&#xff0c;m>0则存在唯一的整数q…

java8中javafx包缺少报错

今天拉取一个jdk1.8的项目里面有一个代码用到了javafx&#xff0c;这个我记得是jdk中的包&#xff0c;正常不应该报错的。然后发现jdk中还真没有&#xff0c;查了一下是因为版本问题。 Java 8 及之前&#xff1a;Oracle JDK 自带 JavaFX&#xff0c;OpenJDK 通常不包含Java 9 …

day072-代码检查工具-Sonar与maven私服-Nexus

文章目录0. 老男孩思想-选对池塘钓美人鱼1. 代码回滚方案2. SonarQube2.1 代码检查工具2.2 部署sonarqube2.2.1 软件要求2.2.2 安装软件2.2.3 启动sonar2.2.4 部署插件2.3 sonar检查java代码2.3.1 创建sona项目2.3.2 分析java代码2.3.3 Jenkins结合sonar检查代码2.4 sonar检查非…

【前端基础】15、列表元素、表格元素、表单元素(注:极其粗略的记载。)

一、列表元素 1、什么是列表元素2、有序列表&#xff08;ol、li&#xff09; ol有序列表 直接子元素只能是li。 li列表中的每一项。3、无序列表&#xff08;ul、li&#xff09; ol无序列表 直接子元素只能是li。 li列表中的每一项。4、定义列表&#xff08;dl、dt、dd&#xff…

IRFBG30PBF Vishay威世MOSFET场效应管

IRFBG30PBF Vishay威世&#xff1a;超快MOSFET 场效应管一、产品定位IRFBG30PBF 是Vishay威世推出的600V/30A N沟道功率MOSFET&#xff0c;采用第五代TrenchFET技术&#xff0c;专为开关电源、电机驱动、新能源逆变器等高功率场景设计。以85mΩ超低导通电阻和超快反向恢复&…

【07-AGI的讨论】

AI ANI&#xff1a;artificial narrow intelligence; 如 智能音箱&#xff1b;自动驾驶汽车&#xff0c;网络搜索&#xff0c;其他用于专业特定事项的工具&#xff1b; AGI&#xff1a;artificial general intelligence; building AI systems that could do anything a typical…

[激光原理与应用-225]:机械 - 3D图与2D图各自的作用

在机械设计与加工领域&#xff0c;3D图和2D图是两种核心的工程表达方式&#xff0c;它们在产品设计、制造、装配及维护等环节中扮演不同角色&#xff0c;具有互补性。以下是它们各自的作用及具体应用场景的详细解析&#xff1a;一、3D图的作用1. 直观展示产品全貌三维可视化&am…

【从零开始java学习|第一篇】java中的名词概念(JDK、JVM、JRE等等)

目录 一、核心运行环境三要素&#xff08;JVM/JRE/JDK&#xff09; 二、常用开发指令&#xff08;JDK 自带工具&#xff09; 三、一些其他概念 四、总结核心逻辑链 要入门 Java&#xff0c;理解核心概念之间的关系是基础。以下是 Java 中最核心的基础概念、工具及相关名词的…

UVa12345 Dynamic len(set(a[L:R]))

[TOC](UVa12345 Dynamic len(set(a[L:R]))) 题目链接 UVA - 12345 Dynamic len(set(a[L:R])) 题意 有编号从 0 到 n−1 的 n 个数&#xff0c;有两种操作&#xff1a; Q L R 询问编号 L 到编号 R−1 的数中有多少个不同的数字。M X Y 将编号为 X 的数字改为 Y。 你的任务就是…

[Ubuntu] VNC连接Linux云服务器 | 实现GNOME图形化

将桌面环境修改为 GNOME 并通过 VNC 远程访问的步骤 & TightVNC 的安装与配置说明&#xff1a;1. 安装 GNOME 桌面环境 sudo apt update sudo apt install ubuntu-gnome-desktop -y2. 安装 TightVNC 服务器 sudo apt install tightvncserver -y3. 初始化 VNC Server 并设置…

进程、网络通信方法

一、进程间通信(IPC)方法 适用于同一台主机上的进程间数据交换。 管道(Pipe) 匿名管道:单向通信,仅用于父子进程。 命名管道(FIFO):通过文件系统路径访问,支持无亲缘关系进程。 消息队列(Message Queue) 结构化消息(类型+数据),按类型读取,支持异步通信。…

[激光原理与应用-241]:设计 - 266n皮秒深紫外激光器,哪些因素影响激光器紫外光的输出功率?

一、短期稳定性266nm皮秒深紫外激光器紫外光输出功率的稳定性受非线性晶体性能、光学系统设计、热管理效果、重复频率与脉冲能量匹配度、环境干扰控制等因素影响&#xff0c;具体分析如下&#xff1a;1. 非线性晶体性能晶体选择与状态&#xff1a;BBO&#xff08;偏硼酸钡&…

Django配置sqllite之外的数据库

当连接到其他数据库后端时&#xff0c;如 MariaDB、MySQL、Oracle 或 PostgreSQL&#xff0c;将需要额外的连接参数。请参阅下面的 ENGINE 配置&#xff0c;了解如何指定其他数据库类型。这个例子是针对 PostgreSQL&#xff1a; 在django项目的settings.py文件里&#xff0c;关…

银河通用招人形机器人强化学习算法工程师了

人形强化学习算法工程师&#xff08;26届&#xff09;&#xff08;岗位信息已通过jobleap.cn授权&#xff0c;可在csdn发布&#xff09;银河通用机器人 北京收录时间&#xff1a; 2025年08月11日职位描述1. 研发基于深度强化学习的足式机器人运动控制算法&#xff0c;提升机器…

使用MongoDB存储和计算距离

一、MongoDB 计算距离的优势 优势说明原生地理空间索引支持 2dsphere 索引&#xff0c;高效处理地理坐标查询&#xff08;毫秒级响应&#xff09;。内置地理计算函数提供 $near、$geoWithin、$geoNear 等操作符&#xff0c;无需手动实现复杂计算。高性能基于B树索引优化&#…