塑料挤出机厂_建仓机械

林芝异型材设备价格 2026-07-31: 好子序列查询。用go言语, 有个长度为 n 的整数数组 n

发布日期:2026-08-01 14:17:44|点击次数:121
塑料管材设备

2026-07-31:好子序列查询。用go言语,有个长度为 n 的整数数组 nums 和个给定的整数 p。界说种“好子序列”:从数组中收用至少个元素、但须至少铁心个元素(即弗成收用一起元素),保捏原有章程所得到的非空序列。如若这个序列中整个元素的大契约数碰劲等于 p林芝异型材设备价格,就称它为好子序列。

接下来会循序践诺 q 次修改操作,每次操作由对下标和数值构成,暗示将该下标位置的元素新为这个新数值。在每次新完成后,王人要判断面前数组是否包含至少个好子序列。

后请统计,在这 q 次查询新中,有若干次新之后数组是存在好子序列的,并复返这个次数。

2

1

1

queries[i] = [indi, vali]

1

0

输入: nums = [4,5,7,8], p = 3, queries = [[0,6],[1,9],[2,3]]。

输出: 2。

讲解:

i

[indi, vali]

操作

新后的 nums

是否存在好子序列

0

[0, 6]

将 nums[0] 新为 6

[6, 5, 7, 8]

否,因为不存在大契约数碰劲为 p = 3 的子序列

1

[1, 9]

将 nums[1] 新为 9

[6, 9, 7, 8]

是,子序列 [6, 9] 的大契约数碰劲为 p = 3

2

[2, 3]

将 nums[2] 新为 3

[6, 9, 3, 8]

是,子序列 [6, 9, 3] 的大契约数碰劲为 p = 3

因此,谜底是 2。

题目来独力扣3901。

算法总体想路

题目要求动态珍惜数组,在每次单点修改后判断是否存在个好子序列。

好子序列须餍足三个条目:

1. 非空;

2. 至少铁心个原数组元素(即弗成取一起);

3. 收用的元素保捏原章程(因为只顺心值,章程不影响 gcd,是以实质只需要商量哪些元素被选);

4. 整个收用元素的 大契约数(gcd)碰劲等于 p。

关节数学质

• 好子序列中每个元素王人须是 p 的倍数,不然 gcd 不可能等于 p。

• 若面前数组中整个 p 的倍数的 gcd 等于 p,何况数组中存在个非 p 的倍数,那么胜仗管用整个 p 的倍数、铁心大肆个非 p 的倍数,即可得到好子序列。

• 若面前数组中整个 p 的倍数的 gcd 等于 p,但数组中一起元素王人是 p 的倍数,则整个这个词数组的 gcd 等于 p,但整个这个词数组弗成被收用。此时需要判断是否存在删除个元素后,剩余 n-1 个数的 gcd 仍然等于 p。这是因为:如若存在职何个真子集的 gcd 等于 p,那么不错迟缓把其他元素加回想,终定存在个大小为 n-1 的子集 gcd 也等于 p,是以只需查验删除个数的情况。

• 反之,如若整个 p 的倍数的 gcd 不等于 p,则定不存在好子序列。

因此,算法中枢是用线段树动态珍惜整个 p 的倍数的集,快速得到它们的 gcd 以及个数。

预解决阶段

1. 输入数组 nums,长度 n,给定整数 p。

2. 创建线段树 SegTree,里面包含:

• tree[]:存储区间内整个 p 的倍数的 gcd(非 p 的倍数用 0 暗示,因为 gcd(0, x) = x,不影响缠绵);

• p:模数;

• cnt:面前数组中 p 的倍数的总个数。

3. 遍历 nums 的每个位置 i:

• 若 nums[i] p == 0,调用线段树的单点新函数,将该位置插入值 nums[i]。

• 每次新会珍惜叶子节点、新里面节点的 gcd,并同步加多 cnt。

4. 运事业态下,线段树根节点 tree[1] 即为面前整个 p 的倍数的 gcd。

每次查询新解决形式

关于每个查询 (idx, val),践诺以下操作:

1. 新数组值:将 nums[idx] 改为 val,同期调用线段树单点新 update(0, n-1, 1, idx, val)。

• 新函数会到达叶子节点 l == r:

• 先查验叶子面前存储的旧值(可能是 0 或原来的 p 的倍数),若旧值非 0 且为 p 的倍数,则 cnt--;

• 再查验新值 val,若 val p == 0,则 cnt++;

• 将叶子存储为 val(若为 p 的倍数)或 0(不然)。

• 回溯时从头缠绵里面节点的 gcd:tree[o] = gcd(tree[o*2], tree[o*2+1])。

2. 此时 nums 已新,cnt 正确林芝异型材设备价格,根节点 tree[1] 是面前整个 p 的倍数的 gcd。

3. 判断是否存在好子序列:

• 令 rtGcd = tree[1]。

• 如若 rtGcd != p,则面前数组不存在好子序列,谜底不加多。

• 如若 rtGcd == p,分两种情况:

• 情况:cnt != n

讲明数组中至少有个元素不是 p 的倍数。

此时收用整个 p 的倍数(个数 ≥ 1,因为 rtGcd == p 意味着存在 p 的倍数),再铁心个非 p 的倍数,这个子序列的 gcd 就等于 rtGcd = p,塑料挤出机且餍足“至少铁心个元素”,是以存在好子序列。谜底加 1。

• 情况二:cnt == n

讲明数组中整个元素王人是 p 的倍数,整个这个词数组的 gcd 即是 rtGcd = p,但整个这个词数组弗成行为子序列(须铁心至少个)。

因此需要判断是否存在个 真子序列 的 gcd 为 p。

证实前边的数学质,只需查验是否存在个元素被删除后,剩余 n-1 个元素的 gcd 仍然等于 p。

• 代码中有个化:若 n > 7,胜仗以为存在好子序列(这是个简化假定,实质可能存在反例,但按代码逻辑践诺)。

• 陈列要删除的下标 i(0 到 n-1);

• 缠绵除了 i 以外整个元素的 gcd;

• 若某轮缠绵得到 gcd == p,讲明存在好子序列,立即复返 true;

• 若整个删除尝试均失败,则不存在。

• 若 deleteOneCheck 复返 true,谜底加 1;不然不加。

4. 整个查询解决竣事后,复返累计的谜底个数。

技巧复杂度

• 线段树建立:运行通过 n 次单点新建立,每次新 O(log n),故 O(n log n)。

• 每次查询:次单点新 O(log n);判断和可能的查验:

• 统统有 q 次查询,因此总技巧复杂度为 O((n + q) log n)。

寥落空间复杂度

• 线段树数组大小为 4n,O(n)。

• 存储 nums 数组 O(n)。

• 递归调用栈度 O(log n)。

• 不商量输入查询 queries 的存储空间,寥落空间为 O(n)。

总结

本算法借助线段树珍惜“整个 p 的倍数”的 gcd 和个数,将动态判断好子序列的存在更动为对根节点 gcd 的分析,并期骗数学质简化了全 p 倍数情况的判断,全体复杂度足以支吾 n, q ≤ 50000 的数据界限。

Go好意思满代码如下:

.

package main

import "fmt"

// 欧几里得算法求大契约数

func gcd(a, b int) int {

for b != 0 {

a, b = b, ab

}林芝异型材设备价格

return a

}

// 线段树结构

type SegTree struct {

tree []int // 存储区间内整个p的倍数的gcd

p int // 模数

cnt int // 面前nums中p的倍数的个数

}

func NewSegTree(n, p int) *SegTree {

return &SegTree{

tree: make([]int, 4*n),

p: p,

cnt: 0,

}

}

// 单点新:将位置i的值改为val,同期珍惜cnt和tree

func (st *SegTree) update(l, r, o, i, val int) {

if l == r {

// 如若旧值正本是p的倍数,则cnt减1

if st.tree[o] != 0 && st.tree[o]st.p == 0 {

st.cnt--

}

// 如若新值是p的倍数,则cnt加1

if valst.p == 0 {林芝异型材设备价格

st.cnt++

}

// 存储值:p的倍数才确凿存储,不然视为0(不影响gcd)

if valst.p == 0 {

st.tree[o] = val

} else {

st.tree[o] = 0

}

return

}

m := (l + r) / 2

if i

st.update(l, m, o*2, i, val)

} else {

st.update(m+1, r, o*2+1, i, val)

}

// 新里面节点的gcd

st.tree[o] = gcd(st.tree[o*2], st.tree[o*2+1])

}

// 当nums中所罕有王人是p的倍数时,尝试删除个数,查验剩尾数的gcd是否等于p

func deleteOneCheck(nums []int, p int) bool {

n := len(nums)

for i := 0; i

curGcd := 0

for j := 0; j

if j == i {

continue

}

curGcd = gcd(curGcd, nums[j])

}

if curGcd == p {

return true

}

}

return false

}

// 主逻辑函数

func countGoodSubseq(nums []int, p int, queries [][]int) int {

n := len(nums)

st := NewSegTree(n, p)

// 运行建立:只将p的倍数插入线段树

for i, v := range nums {

if vp == 0 {

st.update(0, n-1, 1, i, v)

}

}

ans := 0

for _, q := range queries {

idx, val := q[0], q[1]

// 新线段树和nums数组

st.update(0, n-1, 1, idx, val)

nums[idx] = val林芝异型材设备价格

rtGcd := st.tree[1] // 根节点存储的是整个p的倍数的gcd

// 如若整个这个词数组整个p的倍数的gcd碰劲为p,则以为存在个好子序列

if rtGcd == p {

if st.cnt != n {

// 数组中不全是p的倍数

ans++

} else {

// 数组中全是p的倍数,需要寥落判断能否删除个数后使得剩余gcd=p

if n > 7 {

ans++

} else if deleteOneCheck(nums, p) {

ans++

}

}

}

}

return ans

}

func main {

nums := []int{4, 5, 7, 8}

p := 3

queries := [][]int{{0, 6}, {1, 9}, {2, 3}}

result := countGoodSubseq(nums, p, queries)

fmt.Println(result)

}

Python好意思满代码如下:

.

# -*-coding:utf-8-*-

import sys

# 欧几里得算法求大契约数

def gcd(a, b):

while b:

a, b = b, a b

return a

class SegTree:

def __init__(self, n, p):

self.n = n

self.p = p

self.tree = [0] * (4 * n) # 存储区间内整个p的倍数的gcd

self.cnt = 0 # 面前nums中p的倍数的个数

# 单点新:将位置i的值改为val,同期珍惜cnt和tree

def update(self, l, r, o, i, val):

if l == r:

# 如若旧值正本是p的倍数,则cnt减1

if self.tree[o] != 0 and self.tree[o] self.p == 0:

self.cnt -= 1

# 如若新值是p的倍数,则cnt加1

if val self.p == 0:

self.cnt += 1

# 存储值:p的倍数才确凿存储,不然视为0(不影响gcd)

self.tree[o] = val if val self.p == 0 else 0

return

m = (l + r) // 2

if i

self.update(l, m, o * 2, i, val)

else:

self.update(m + 1, r, o * 2 + 1, i, val)

# 新里面节点的gcd

self.tree[o] = gcd(self.tree[o * 2], self.tree[o * 2 + 1])

# 当nums中所罕有王人是p的倍数时,尝试删除个数,查验剩尾数的gcd是否等于p

def delete_one_check(nums, p):

n = len(nums)

for i in range(n):

cur_gcd = 0

for j in range(n):

if j == i:

continue

cur_gcd = gcd(cur_gcd, nums[j])

if cur_gcd == p:

return True

return False

def count_good_subseq(nums, p, queries):

n = len(nums)

st = SegTree(n, p)

# 运行建立:只将p的倍数插入线段树

for i, v in enumerate(nums):

if v p == 0:

st.update(0, n - 1, 1, i, v)

ans = 0

for idx, val in queries:

# 新线段树和nums数组

st.update(0, n - 1, 1, idx, val)

nums[idx] = val

rt_gcd = st.tree[1] # 根节点存储的是整个p的倍数的gcd

# 如若整个这个词数组整个p的倍数的gcd碰劲为p,则以为存在个好子序列

if rt_gcd == p:

if st.cnt != n:

# 数组中不全是p的倍数

ans += 1

else:

# 数组中全是p的倍数,需要寥落判断能否删除个数后使得剩余gcd=p

if n > 7:

ans += 1

elif delete_one_check(nums, p):

ans += 1

return ans

def main:

nums = [4, 5, 7, 8]

p = 3

queries = [[0, 6], [1, 9], [2, 3]]

result = count_good_subseq(nums, p, queries)

print(result)

if __name__ == "__main__":

main

C++好意思满代码如下:

.

#include

#include

using namespace std;

// 欧几里得算法求大契约数

int gcd(int a, int b) {

while (b != 0) {

int t = a b;

a = b;

b = t;

}

return a;

}

// 线段树类

class SegTree {

public:

vector tree; // 存储区间内整个 p 的倍数的 gcd

int p; // 模数

int cnt; // 面前 nums 中 p 的倍数的个数

SegTree(int n, int p_) : p(p_), cnt(0) {

tree.assign(4 * n + 5, 0);

}

// 单点新:将位置 i 的值改为 val,同期珍惜 cnt 和 tree

void update(int l, int r, int o, int i, int val) {

if (l == r) {

int old = tree[o]; // 旧值(0 暗示非 p 的倍数)

// 如若旧值正本是 p 的倍数,则 cnt 减 1

if (old != 0 && old p == 0) {

cnt--;

}

// 如若新值是 p 的倍数,则 cnt 加 1

if (val p == 0) {

cnt++;

}

// 存储值:p 的倍数才确凿存储,不然视为 0(不影响 gcd)

tree[o] = (val p == 0) ? val : 0;

return;

}

int m = (l + r) / 2;

if (i

update(l, m, o * 2, i, val);

} else {

update(m + 1, r, o * 2 + 1, i, val);

}

// 新里面节点的 gcd

tree[o] = gcd(tree[o * 2], tree[o * 2 + 1]);

}

};

// 当 nums 中所罕有王人是 p 的倍数时,尝试删除个数,查验剩尾数的 gcd 是否等于 p

bool deleteOneCheck(const vector& nums, int p) {

int n = (int)nums.size;

for (int i = 0; i

int curGcd = 0;

for (int j = 0; j

if (j == i) continue;

curGcd = gcd(curGcd, nums[j]);

}

if (curGcd == p) {

return true;

}

}

return false;

}

// 主逻辑函数

int countGoodSubseq(vector& nums, int p, const vector>& queries) {

int n = (int)nums.size;

SegTree st(n, p);

// 运行建立:只将 p 的倍数插入线段树

for (int i = 0; i

if (nums[i] p == 0) {

st.update(0, n - 1, 1, i, nums[i]);

}

}

int ans = 0;

for (const auto& q : queries) {

int idx = q[0], val = q[1];

// 新线段树和 nums 数组

st.update(0, n - 1, 1, idx, val);

nums[idx] = val;

int rtGcd = st.tree[1]; // 根节点存储的是整个 p 的倍数的 gcd

// 如若整个这个词数组整个 p 的倍数的 gcd 碰劲为 p,则以为存在个好子序列

if (rtGcd == p) {

if (st.cnt != n) {

// 数组中不全是 p 的倍数

ans++;

} else {

// 数组中全是 p 的倍数,需要寥落判断能否删除个数后使得剩余 gcd = p

if (n > 7) {

ans++;

} else if (deleteOneCheck(nums, p)) {

ans++;

}

}

}

}

return ans;

}

int main {

vector nums = {4, 5, 7, 8};

int p = 3;

vector> queries = {{0, 6}, {1, 9}, {2, 3}};

int result = countGoodSubseq(nums, p, queries);

cout

return 0;

}

·

咱们服气东谈主工智能为肤浅东谈主提供了种“增强用具”,并勉力于共享全位的AI学问。在这里,您不错找到新的AI科普著述、用具评测、擢升率的心事以及行业细察。

接待关注“福大大架构师逐日题”,发音问可获取口试而已,让AI助力您的翌日发展。Q Q:183445502相关词条:管道保温施工     塑料挤出设备     预应力钢绞线    玻璃棉厂家    保温护角专用胶

1.本网站以及本平台支持关于《新广告法》实施的“极限词“用语属“违词”的规定,并在网站的各个栏目、产品主图、详情页等描述中规避“违禁词”。
2.本店欢迎所有用户指出有“违禁词”“广告法”出现的地方,并积极配合修改。
3.凡用户访问本网页,均表示默认详情页的描述林芝异型材设备价格,不支持任何以极限化“违禁词”“广告法”为借口理由投诉违反《新广告法》,以此来变相勒索商家索要赔偿的违法恶意行为。

Powered by 塑料挤出机厂_建仓机械 RSS地图 HTML地图

Copyright Powered by365站群 © 2025-2035