1. 整数转变
开始有一个整数 b,你需要经过若干次操作,使 n 的值不小于 m 。
- 操作一:将 $n$ 更改为 $2 * n$ ,花费为 $w_2$
- 操作二:将 $n$ 更改为 $3 * n$ ,花费为 $w_3$
请输出需要的最小花费。
输入描述
- 输入第一行一个整数 $T$,代表接下来有 $T$ 组测试数据。接下来 $T$ 行,每行有 4 个整数 $n,m,w_2,w_3$
- $1< T < 10000$
- $1< n,m < 2^{31}-1$
- $1< w_2,w_3 < 1000$
输出描述
- 对于每组测试数据,输出一行,一个整数代表最小花费
示例 1
输入:
1 | 4 |
输出:
1 | 5 |
代码:动态规划(记忆化搜索 + 哈希表 memo)
记忆化搜索,这个题不可以使用迭代的动态规划来完成,会超时,记忆化搜索可以跳过非常多不必要考虑的状态(因为使用了 unordered_map
而非 vector
,省去了逐个遍历的时间)。
1 |
|
2. 漂亮数
我们定义一个漂亮数是这样的数:
- 该数为正整数
- 设该数为 x,存在一个质数 p 使得
x mod p = 0
且p * p >= x
给你一个正整数 n,你能否求出有多少漂亮数小于等于 n?
输入描述
- 输入一行一个正整数 $n(1 < n < 5 * 10^6)$
输出描述
- 输出一行一个正整数,代表小于等于 n 的漂亮数的个数。
示例 1
输入:
1 | 10 |
输出:
1 | 8 |
解释:10 以内除了 1 和 8 都是漂亮数
代码:数论
- 筛质数
- 基于最小质因数,递推计算每个数的最大质因数。
1 |
|
3. 最长路径
游游很喜欢树,这一天他在研究树上的路径,他遇到了一个难题,现在邀请你帮助他解决该问题。
在一棵树上,两个点并不一定能确定一条链,但是可以找到一条经过这两个点最长的一条链。
你有一棵 n 个点的树,树上每条边都有一个权值,定义一条简单路径的长度为这条简单路径上的边权和,对于给定的两个点 x, y,你需要回答在树上经过这两个点的最长简单路径是多少。
树上的路径:从节点 u 到节点 v 的简单路径定义为从节点 u 出发,以节点 v 为终点,随意在树上走,不经过重复的点和边走出来的序列。可以证明,在树上,任意两个节点间有且仅有一条简单路径。
输入描述
- 第一行两个数 $n, m (1< n, m < 10^5)$
- 接下来 $n - 1$ 行,每行 3 个数 $u_i, v_i, d_i (1 < u_i, v_i < n, 1 < d_i <10^9)$,表示树的第 $i$ 条边
- 接下来 $m$ 行,每行 2 个数 $x, y$,表示一次询问。
输出描述
- 共 m 行,每行一个整数 ans,表示你的答案
示例 1
输入:
1 | 4 4 |
输出:
1 | 3 |
代码:LCA(最近公共祖先)
路径由三部分组成:
- 起点 a 到 x:选一个能离 x 最远的点 a(不能往 y 方向走)
- x 到 y:这是唯一的固定路径
- y 到终点 b:选一个能离 y 最远的点 b(不能往 x 方向走)
总长度就是这三段距离的和。核心是找到 a 和 b 这两个“最远端点”。
为了快速计算,需要提前准备三个重要信息:
向下最长路径(子树方向)
用深度优先搜索(DFS)从根节点出发,记录每个节点 u 的两个值:
down1[u]
:u 向下走到子树的最长路径(比如 u→ 子节点 v → … → 叶子)down2[u]
:次长路径(必须走不同子节点)
同时记录
down1_child[u]
表示哪个子节点贡献了最长路径
向上最长路径(父节点方向)
第二次 DFS 计算
up[u]
,表示从u向上走(经过父节点)的最长路径。这里要考虑两种情况:如果父节点的最长路径经过 u → 只能用父节点的次长路径
否则 → 可以用父节点的最长路径
比如父节点 p 的最长路径是 p→q,而 u 是 p 的子节点但不是 q,则
up[u] = up[p] + 边权
LCA(最近公共祖先)
用倍增法预处理每个节点的 $2^k$ 级祖先,快速计算 x 和 y 的距离:
dist(x,y) = 到根的距离x + 到根的距离y - 2 * 到根的距离(lca(x,y))
:这能快速得到 x 到 y 的路径长度
对于每个查询 $(x,y)$,分情况处理:
x 和 y 是同一个点:最长路径要么是向下走两条分支(down1 + down2),要么是向上走再向下(up + down1)
x 和 y 不同
分三步计算:
确定路径方向:
找到 x 到 y 路径上的邻居节点 nx(如果 y 在 x 的子树里,nx 是 x 的子节点;否则是 x 的父节点)
同理找到 y 的邻居 ny
计算
max_dist_x
(不经过 nx 的最远距离):如果 nx 是父节点 → 只能向下走,取
down1[x]
如果 nx 是子节点 → 比较向上(
up[x]
)和向其他子节点的路径(down1 或 down2)
同样计算
max_dist_y
,最终总长度是这三部分的和
1 |
|