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

Kimi LeetCode 3525. 求出数组的 X 值 II Python3实现

以下是 LeetCode 3525 求出数组的 X 值 II 的 Python3 实现,核心思路是线段树维护区间前缀积的模分布。

思路概述

- 对于每个查询,先单点修改 `nums[index]`,再移除前缀保留 `[start..]`,最后可以删除任意后缀(即保留任意非空前缀)。
- 因此每个查询的答案等价于:在子数组 `nums[start..]` 的所有非空前缀中,乘积模 `k` 等于 `x` 的个数。
- 由于 `k ≤ 5`,线段树每个节点只需维护:
- `prod`:区间整体乘积模 `k`
- `cnt`:`cnt[m]` 表示该区间内,有多少个非空前缀的乘积模 `k` 等于 `m`
- 合并两个子区间时,右子树的前缀需要乘上左子树的总积再模 `k`。

复杂度

- 时间:`O((n + q) · k² · log n)`,由于 `k ≤ 5`,实际约为 `O((n + q) log n)`
- 空间:`O(n)`

完整代码

```python
class Node:
__slots__ = ('prod', 'cnt')
def __init__(self):
self.prod = 1 # 区间乘积 % k
self.cnt = [0] * 5 # cnt[m] = 非空前缀中乘积 % k == m 的个数

class SegTree:
def __init__(self, nums, k):
self.n = len(nums)
self.k = k
self.tree = [Node() for _ in range(self.n * 4)]
self.build(1, 0, self.n - 1, nums)

def build(self, node, l, r, nums):
if l == r:
v = nums[l] % self.k
self.tree[node].prod = v
self.tree[node].cnt = [0] * 5
self.tree[node].cnt[v] = 1
return
mid = (l + r) >> 1
self.build(node << 1, l, mid, nums)
self.build(node << 1 | 1, mid + 1, r, nums)
self.pull(node)

def merge(self, left, right):
res = Node()
res.prod = (left.prod * right.prod) % self.k

# 左区间的前缀直接保留
for i in range(self.k):
res.cnt[i] += left.cnt[i]

# 右区间的前缀需要乘上左区间的总积
for i in range(self.k):
if right.cnt[i]:
new_mod = (left.prod * i) % self.k
res.cnt[new_mod] += right.cnt[i]

return res

def pull(self, node):
self.tree[node] = self.merge(self.tree[node << 1], self.tree[node << 1 | 1])

def update(self, node, l, r, idx, val):
if l == r:
v = val % self.k
self.tree[node].prod = v
self.tree[node].cnt = [0] * 5
self.tree[node].cnt[v] = 1
return
mid = (l + r) >> 1
if idx <= mid:
self.update(node << 1, l, mid, idx, val)
else:
self.update(node << 1 | 1, mid + 1, r, idx, val)
self.pull(node)

def query(self, node, l, r, ql, qr):
if ql <= l and r <= qr:
return self.tree[node]
mid = (l + r) >> 1
if qr <= mid:
return self.query(node << 1, l, mid, ql, qr)
if ql > mid:
return self.query(node << 1 | 1, mid + 1, r, ql, qr)
left = self.query(node << 1, l, mid, ql, qr)
right = self.query(node << 1 | 1, mid + 1, r, ql, qr)
return self.merge(left, right)

class Solution:
def resultArray(self, nums: List[int], k: int, queries: List[List[int]]) -> List[int]:
n = len(nums)
# 预处理:所有数先对 k 取模
nums = [x % k for x in nums]

seg = SegTree(nums, k)
ans = []

for q in queries:
idx, val, start, x = q
val %= k
seg.update(1, 0, n - 1, idx, val)
res = seg.query(1, 0, n - 1, start, n - 1)
ans.append(res.cnt[x])

return ans
```

关键点说明

1. `cnt` 的含义:每个节点维护的是从该区间左端点开始的所有非空前缀的模分布。这样查询任意子区间时,递归返回的子节点天然满足"从左端点开始"的要求,合并时只需把右子树的前缀乘上左子树的总积即可。
2. `k ≤ 5` 的利用:`cnt` 数组固定开 5,实际只用前 `k` 个;合并时的双重循环最多 25 次运算,常数极小。
3. 单点更新:修改叶子后自底向上 `pull`,保持每个节点的 `prod` 和 `cnt` 正确。
4. 预处理取模:建树前和更新时都把数值对 `k` 取模,避免大数运算。

http://www.jsqmd.com/news/1160118/

相关文章:

  • shell环境变量
  • Muse Image:基于扩散模型的社交媒体图像生成技术解析
  • VB6.0在Windows 10/11上的兼容性安装与运行时修复指南
  • 它们由权重构成:揭秘大模型背后的灵魂架构
  • 市场分析PPT模板推荐哪家?2026年超全选购指南
  • STM32F411RE与L9958实现高性能BLDC电机驱动方案
  • 微机课设核心器件解析:8255与DAC0832在8086波形发生器中的3种典型接口电路
  • 信息素养大赛 C++ 复赛真题精讲:从“滑雪板打包”到“选书方案”的 2 种优化策略
  • ANSYS 2026安装架构深度解析:HPC运行时、许可证机制与Windows部署陷阱
  • 3分钟整理Windows右键菜单:ContextMenuManager让你的桌面效率翻倍
  • 阴阳师自动化脚本终极指南:三步解决模拟器适配难题
  • 基于蓝牙5.4与STM32的高性能无线音频系统设计
  • Creo 10.0教育版合法安装与工程级配置指南
  • 卡地亚中国官方售后服务中心|地址与官方服务热线权威信息公告(2026年7月最新) - 卡地亚服务中心
  • 基础 1 —— Docker 的简介
  • 江西省赣州市兴国县九里蓝湾六层别墅电梯落地:主梁加固后现浇土建井道,木纹定制家用电梯安全交付
  • Ansible远程管理飞牛OS实操:Playbook执行、SSH穿透与固定TCP地址配置
  • 逸程扎根南京秦淮 专业黄金回收鉴定服务 - 融媒生活
  • 2026多商户商城系统哪家好,别被功能清单带偏
  • 旧金回收卖高价 南京秦淮实用方法分享 - 融媒生活
  • SEO 优化哪个公司好?业内公认实力强的 SEO 优化企业推荐 - 品牌推荐大师
  • 亚马逊自研AI芯片技术解析:从架构设计到设备端应用
  • Linux核心运维命令
  • Transformer 注意力简化运算:CCF-CSP 202305-2 矩阵题 2 种实现对比
  • 直流有刷电机驱动方案:TC78H651AFNG与PIC18F4585的优化设计
  • 高温SAW传感器设计避坑:薄膜脱湿(Dewetting)的7种抑制方法与实测案例
  • 平板配件制造的进化逻辑:铭宏智造的工程化思维与市场适配实践 - 资讯焦点
  • 2026 深圳品牌首饰回收用户真实反馈合集|首榜易奢福线下门店全品类首饰探店测评 - ys韩
  • TS2007FC与PIC18F4620实现低功耗高音质音频系统设计
  • 大模型入门指南:小白程序员轻松掌握LLM应用开发,收藏必备!