2025-11-18:分割数组后不同质数的最大数目 用go语言,给定一个

B站影视 韩国电影 2025-11-18 06:31 1

摘要:2025-11-18:分割数组后不同质数的最大数目。用go语言,给定一个长度为 n 的整数数组 nums 和若干查询,每个查询由一对整数 queries[i] = [idx, val] 表示。

2025-11-18:分割数组后不同质数的最大数目。用go语言,给定一个长度为 n 的整数数组 nums 和若干查询,每个查询由一对整数 queries[i] = [idx, val] 表示。

对每一次查询,先把 nums[idx] 改为 val(这个修改会影响后续的查询)。然后你可以在 1 到 n-1 之间选一个分割点 k,把数组分成不为空的前半段 nums[0..k-1] 和后半段 nums[k..n-1]。对于每一段,统计其中不同的质数的个数(质数指大于 1 且只有 1 和自身两个约数的正整数),将前后两段的这两个计数相加。你需要选取使这个和尽可能大的分割点 k。

返回一个长度与查询数相同的数组,按查询顺序给出每次操作后能得到的最大和。

2

1

1

0

1

输入: nums = [2,1,3,1,2], queries = [[1,2],[3,3]]。

输出: [3,4]。

解释:

初始时 nums = [2, 1, 3, 1, 2]。

在第一次查询后,nums = [2, 2, 3, 1, 2]。将 nums 分为 [2] 和 [2, 3, 1, 2]。[2] 包含 1 个不同的质数,[2, 3, 1, 2] 包含 2 个不同的质数。所以此查询的答案是 1 + 2 = 3。

在第二次查询后,nums = [2, 2, 3, 3, 2]。将 nums 分为 [2, 2, 3] 和 [3, 2],其答案为 2 + 2 = 4。

最终输出为 [3, 4]。

题目来自力扣3569。

以下是对给定Go代码处理"分割数组后不同质数的最大数目"问题的详细分步描述。算法核心在于动态维护数组状态,并通过高效数据结构快速计算每次更新后的最优分割点。

埃拉托斯特尼筛法预处理:首先使用埃拉托斯特尼筛法预计算1到100,000(常数mx = 1e5)范围内所有数字的质数状态。结果存储在布尔数组np中,np[i]为true表示i不是质数。这使得后续质数判断可在O(1)时间内完成。

初始化数据结构

创建一个映射pos,键为质数值,值为红黑树(Red-Black Tree),用于存储该质数在数组nums中出现的所有索引位置。红黑树支持高效插入、删除和查询最值操作。初始化一个懒惰线段树(Lazy Segment Tree),大小为数组长度n,初始值全为0。该线段树用于维护每个可能分割点k对应的"额外收益"。若元素是质数(通过np数组检查),将其索引加入对应质数值的红黑树中。

构建线段树初始状态:对于每个出现至少两次的质数(即其红黑树大小 > 1):

设该质数在数组中的最小索引为L,最大索引为R。在线段树的区间[L, R]上执行加1操作。这表示若分割点k落在L和R之间(含端点),该质数会同时出现在前后两段,从而为总贡献带来+1的"额外收益"。

更新数组值:将nums[idx]修改为新值val。

处理旧值(若为质数)

从旧值对应的红黑树中移除索引idx。若移除后该红黑树为空,则从映射pos中删除此质数。若红黑树非空(即该质数仍存在),更新线段树:设当前最小索引为L,最大索引为R。根据被移除的索引idx与L、R的关系,调整线段树区间:若idx是唯一索引(L == R),更新区间[min(L, idx), max(R, idx)],值减1。若idx 若idx > R,更新区间[R+1, idx],值减1。此操作确保线段树准确反映该质数当前索引范围对分割点的影响。

处理新值(若为质数)

若新值val不在pos中,为其新建一个红黑树。将索引idx加入val对应的红黑树。若红黑树大小 > 1(即该质数现多次出现),更新线段树:逻辑同旧值处理,但执行加1操作,以添加新索引带来的影响。

计算当前查询的答案

当前数组中不同质数的总数 = len(pos)。查询线段树整个区间[0, n-1]的最大值,该值表示所有可能分割点k中,能同时使最多质数出现在两段中的"额外收益"最大值。答案 = len(pos) + 线段树最大值。这是因为总分由两部分组成:基础值:不同质数总数(每个质数至少贡献1)。额外收益:若分割点使某个质数同时出现在两段,则该质数多贡献1。

分割点选择:分割点k取值范围为1到n-1,线段树自动维护每个k对应的收益,无需显式遍历所有k。

懒惰线段树的作用:支持区间加减和区间最大值查询,均可在O(log n)时间内完成,确保高效性。

红黑树的作用:快速获取质数索引的最小值/最大值,并在索引变化时动态维护。

预处理

埃拉托斯特尼筛法:O(mx log log mx) ≈ O(10^5 log log 10^5),可视为常数时间。初始化红黑树和线段树:O(n log n)。

每个查询处理

红黑树插入/删除:O(log n)。线段树更新:O(log n)。线段树查询最大值:O(1)(直接访问根节点值)。

总体:O(n log n + q log n),其中n为数组长度,q为查询数量。

筛法数组:O(mx) = O(10^5),常数空间。

红黑树映射:最坏情况下存储O(n)个索引。

线段树:O(n)空间。

总体:O(n)(忽略常数项)。

该算法通过结合筛法、红黑树和线段树,高效处理了动态数组下的最优分割问题。

package mainimport ( "fmt" "math/bits" "github.com/emirpasic/gods/v2/trees/redblacktree")const mx int = 1e5var np = [mx + 1]bool{true, true}func init { for i := 2; i > 1 t.build(a, o> 1 if l > 1 if r m { return t.query(oif _, ok := pos[x]; !ok { pos[x] = redblacktree.New[int, struct{}] } pos[x].Put(i, struct{}{}) } t := newLazySegmentTree(n, 0) for _, ps := range pos { if ps.Size > 1 { t.update(1, ps.Left.Key, ps.Right.Key, 1) } } update := func(ps *redblacktree.Tree[int, struct{}], i, delta int) { l, r := ps.Left.Key, ps.Right.Key if l == r { t.update(1, min(l, i), max(r, i), delta) } elseif i r { t.update(1, r+1, i, delta) } } for _, q := range queries { i, v := q[0], q[1] old := nums[i] nums[i] = v // 处理旧值 if !np[old] { ps := pos[old] ps.Remove(i) if ps.Empty { delete(pos, old) } else { update(ps, i, -1) } } // 处理新值 if !np[v] { if ps, ok := pos[v]; !ok { pos[v] = redblacktree.New[int, struct{}] } else { update(ps, i, 1) } pos[v].Put(i, struct{}{}) } // 整个数组的不同质数个数 + 切一刀的最大额外收益 ans = append(ans, len(pos)+t.query(1, 0, n-1)) } return } func main { nums := int{2, 1, 3, 1, 2} queries := int{{1, 2}, {3, 3}} result := maximumCount(nums, queries) fmt.Println(result) } # -*-coding:utf-8-*-from sortedcontainers import SortedSetimport mathmx = 10**5np = [False] * (mx + 1)np[0] = np[1] = True# 质数筛for i in range(2, mx + 1): if not np[i]: for j in range(i*i, mx + 1, i): np[j] = True# # 懒标记线段树:区间加 + 区间最大值# class LazySegTree: def __init__(self, a): n = len(a) size = 1 1: l, r = ps[0], ps[-1] t.update(l, r, 1) def update(ps, i, delta): l, r = ps[0], ps[-1] if l == r: L = min(l, i) R = max(r, i) t.update(L, R, delta) elif i r: t.update(r + 1, i, delta) ans = for i, v in queries: old = nums[i] nums[i] = v # 删除旧值 if not np[old]: ps = pos[old] ps.remove(i) iflen(ps) == 0: del pos[old] else: update(ps, i, -1) # 插入新值 if not np[v]: if v not in pos: pos[v] = SortedSet else: update(pos[v], i, 1) pos[v].add(i) # 输出结果 ans.append(len(pos) + t.query(0, n - 1)) return ans# # 测试# if __name__ == "__main__": nums = [2, 1, 3, 1, 2] queries = [[1, 2], [3, 3]] print(maximumCount(nums, queries))#include using namespace std; constint MX = 100000; bool np[MX + 1]; // 非质数标记 struct Node { int l, r; int mx; int todo; }; struct LazySeg { vectort; int n; LazySeg(int n, int initVal) : n(n) { int size = 2 > 1; build(a, o > 1; if (l > 1; if (r m) return query(o & queries) { int n = nums.size; unordered_map> pos; for (int i = 0; i 1) { int l = mp.begin->first; int r = mp.rbegin->first; t.update(1, l, r, 1); } } auto update = [&](map& mp, int i, int delta) { int l = mp.begin->first; int r = mp.rbegin->first; if (l == r) { t.update(1, min(l, i), max(r, i), delta); } elseif (i r) { t.update(1, r + 1, i, delta); } }; vectorans; for (auto &q : queries) { int i = q[0], v = q[1]; int old = nums[i]; nums[i] = v; if (!np[old]) { auto& mp = pos[old]; mp.erase(i); if (mp.empty) { pos.erase(old); } else { update(mp, i, -1); } } if (!np[v]) { auto &mp = pos[v]; if (!mp.empty) update(mp, i, 1); mp[i] = 1; } ans.push_back((int)pos.size + t.query(1, 0, n - 1)); } return ans; } int main { vectornums = {2, 1, 3, 1, 2}; vector> queries = {{1, 2}, {3, 3}}; vectorresult = maximumCount(nums, queries); for (int x : result) cout

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。

·

来源:湖南教育网资讯

相关推荐