news 2026/8/18 11:49:25

Kimi LeetCode 3939. 统计有根树中不相邻子集的数目 Rust实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kimi LeetCode 3939. 统计有根树中不相邻子集的数目 Rust实现

LeetCode 3939. 统计有根树中不相邻子集的数目 — Rust 实现

题目概述

给定一棵有根树(`n ≤ 1000`),每个节点有权值 `nums[i]`。要求统计非空子集的数量,满足:
1. 子集中节点权值之和能被 `k` 整除(`k ≤ 100`)
2. 子集中任意两个节点在树中不相邻(父子不能同时选)

结果对 `10^9 + 7` 取模。

解题思路:树上 DP

对每个节点 `u`,维护两个长度为 `k` 的 DP 数组:

状态 含义
`dp0[mod]` 不选节点 `u`,其子树中选出一些不相邻节点,和模 `k` 为 `mod` 的方案数
`dp1[mod]` 选节点 `u`,其子树中选出一些不相邻节点,和模 `k` 为 `mod` 的方案数

转移:
- 当前节点不选:子节点可选可不选

```
dp0_new[(a+b)%k] += dp0[a] * (child_dp0[b] + child_dp1[b])
```

- 当前节点选:子节点不能选

```
dp1_new[(a+b)%k] += dp1[a] * child_dp0[b]
```

初始化:
- `dp0[0] = 1`(不选当前节点,空集)
- `dp1[nums[u] % k] = 1`(选当前节点)

答案: `(dp0_root[0] + dp1_root[0] - 1) % MOD`,减 1 是排除空集。

时间复杂度:`O(n · k²)`,空间复杂度:`O(n · k)`。

---

Rust 代码

```rust
use std::collections::HashMap;

const MOD: i64 = 1_000_000_007;

impl Solution {
pub fn count_valid_subsets(parent: Vec<i32>, nums: Vec<i32>, k: i32) -> i32 {
let n = parent.len();
let k = k as usize;

// 构建邻接表(子节点列表)
let mut children: Vec<Vec<usize>> = vec![vec![]; n];
for i in 1..n {
let p = parent[i] as usize;
children[p].push(i);
}

// DFS 返回 (dp0, dp1)
// dp0[mod]: 不选当前节点,子树和模k为mod的方案数
// dp1[mod]: 选当前节点,子树和模k为mod的方案数
fn dfs(u: usize, children: &Vec<Vec<usize>>, nums: &Vec<i32>, k: usize) -> (Vec<i64>, Vec<i64>) {
let mut dp0 = vec![0i64; k];
let mut dp1 = vec![0i64; k];

// 初始化
dp0[0] = 1; // 不选u,空集
dp1[(nums[u] as usize) % k] = 1; // 选u

for &v in &children[u] {
let (child_dp0, child_dp1) = dfs(v, children, nums, k);

let mut new_dp0 = vec![0i64; k];
let mut new_dp1 = vec![0i64; k];

// 当前节点不选:子节点可选可不选
for i in 0..k {
if dp0[i] == 0 { continue; }
for j in 0..k {
if child_dp0[j] == 0 && child_dp1[j] == 0 { continue; }
let ways = (child_dp0[j] + child_dp1[j]) % MOD;
let ni = (i + j) % k;
new_dp0[ni] = (new_dp0[ni] + dp0[i] * ways) % MOD;
}
}

// 当前节点选:子节点不能选
for i in 0..k {
if dp1[i] == 0 { continue; }
for j in 0..k {
if child_dp0[j] == 0 { continue; }
let ni = (i + j) % k;
new_dp1[ni] = (new_dp1[ni] + dp1[i] * child_dp0[j]) % MOD;
}
}

dp0 = new_dp0;
dp1 = new_dp1;
}

(dp0, dp1)
}

let (dp0_root, dp1_root) = dfs(0, &children, &nums, k);
let ans = (dp0_root[0] + dp1_root[0] - 1 + MOD) % MOD;
ans as i32
}
}
```

---

代码要点说明

1. 取模处理:Rust 中负数取模需要小心,最后答案用 `(ans + MOD) % MOD` 保证非负。
2. 递归 DFS:由于 `n ≤ 1000`,递归深度安全。
3. 状态合并:对每个子节点做背包式合并,复杂度 `O(k²)`。
4. 空集排除:`dp0[0] = 1` 表示不选任何节点的空集,最终答案需要减 1。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 11:44:11

为什么同样成绩会被调整?VCEModeration到底在做什么

有不少VCE学生曾历经这般情况: SAC成绩揭晓时, 自认为状况尚可不错, 然而最终的study score同自身预先期望相距甚是遥远。 问老师&#xff0c;老师说"经过之后的结果"。 问&#xff1a;什么是&#xff1f; 解释往往很模糊&#xff0c;或者就是一句"VCAA统一调…

作者头像 李华
网站建设 2026/8/18 11:41:29

蔚来ES8中期改款解析:智能座舱与三电系统升级成核心

1. 谍照解读&#xff1a;新款ES8的“变”与“不变”最近&#xff0c;网上又流出了一组新款蔚来ES8的测试车谍照。说实话&#xff0c;第一眼看到这组照片&#xff0c;很多人的第一反应可能和我一样&#xff1a;“这变化好像不大啊&#xff1f;” 外观内饰的改动看起来相当克制&a…

作者头像 李华
网站建设 2026/8/18 11:37:25

Adobe-GenP 3.0深度解析:一文搞定Adobe CC 2019–2023全家桶激活

Adobe-GenP 3.0深度解析&#xff1a;一文搞定Adobe CC 2019–2023全家桶激活 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP 周四深夜十一点&#xff0c;设计工作室…

作者头像 李华