n的约数(约数统计+dfs)

578 篇文章 ¥299.90 ¥399.90
570 篇文章 ¥299.90 ¥399.90
该博客探讨了一种使用深度优先搜索(DFS)方法来解决关于寻找[1, n]区间内约数个数最多数的约数个数的问题。文章详细介绍了题目描述,输入输出格式,并可能涉及数学和算法知识。" 114349385,10548120,Java 死锁详解:原因、条件与预防策略,"['Java', '多线程', '并发编程', '死锁预防', '资源管理']
链接: https://www.nowcoder.com/acm/contest/82/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

t次询问,每次给你一个数n,求在[1,n]内约数个数最多的数的约数个数

输入描述:

第一行一个正整数t
之后t行,每行一个正整数n

输出描述:

输出t行,每行一个整数,表示答案
这是一个典型的图论问题,我们可以将满足条件的数之间的变换看作图中的边,然后寻找图中最长的路径(不重复节点的路径),这可以使用深度优先搜索(DFS)结合树形动态规划(树形DP)来解决。 ### 解题思路: 1. **预处理约数和**: - 首先计算出每个数 `x` 的真约数之和 `y`(即不包括 `x` 本身的所有正约数之和),如果 `y <= n` 且 `y != x`,那么我们就建立一条边 `x -> y`。 - 这样构建出一个有向图。 2. **构建图的邻接表**: - 使用一个数组 `vector<int> adj[n+1]` 来保存图的邻接关系。 3. **DFS + 记忆化搜索**: - 对于每个节点,使用 DFS 搜索最长路径,并记录已经计算过的节点的最大路径长度(记忆化),避免重复计算。 4. **维护最大步数**: - 在所有节点中找出最长路径的长度,即为所求的最大变换步数。 --- ### C++ 实现代码如下: ```cpp #include <iostream> #include <vector> #include <cmath> using namespace std; const int MAXN = 50005; int n; int divisor_sum[MAXN]; // 存储每个数的真约数和 int dp[MAXN]; // dp[i] 表示从i出发的最长路径长度 bool visited[MAXN]; // 计算每个数的真约数和 void computeDivisorSum() { for (int i = 1; i <= n; ++i) { for (int j = 2 * i; j <= n; j += i) { divisor_sum[j] += i; } } } // DFS + 树形DP int dfs(int u) { if (visited[u]) return dp[u]; visited[u] = true; int max_len = 0; int v = divisor_sum[u]; if (v <= n && v != u) { max_len = dfs(v) + 1; } dp[u] = max_len; return dp[u]; } int main() { cin >> n; computeDivisorSum(); int max_steps = 0; for (int i = 1; i <= n; ++i) { if (!visited[i]) { int len = dfs(i); max_steps = max(max_steps, len); } } cout << max_steps << endl; return 0; } ``` --- ### 解释: - `computeDivisorSum()` 函数通过倍数法快速计算每个数的真约数和。 - `dfs(int u)` 函数从 `u` 开始搜索最长变换路径,使用 `dp[u]` 缓存结果,避免重复计算。 - `max_steps` 维护全局最长路径长度。 --- ### 示例输入输出: 输入: ``` 7 ``` 输出: ``` 3 ``` 解释:一种变换路径是 `4 → 3 → 1 → 7`,共3步。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值