1 条题解
-
0
题解:集合 的第 个元素
解题思路
题目要求我们生成一个集合 ,集合中的元素按照以下规则生成:
- 初始元素是 。
- 如果 在 中,那么 和 也在 中。
- 集合 中的元素按递增顺序排列,需要找到第 个元素。
这个问题类似于生成一个有序序列,其中每个新元素都是由已有元素通过两种规则生成的。为了高效生成这个序列,可以采用类似“归并排序”的方法,动态维护两个指针,分别指向当前可以通过 和 生成最小候选值的位置。
分析
-
序列生成规则:
- 初始时,序列的第一个元素是 。
- 后续的每个元素都是通过已有元素的 或 生成的。
- 为了保证序列有序,每次选择最小的候选值加入序列。
-
动态维护候选值:
- 用两个指针 和 分别指向当前可以通过 和 生成最小候选值的位置。
- 每次比较 和 ,选择较小的加入序列,并移动对应的指针。
-
避免重复:
- 如果两个候选值相等,需要同时移动两个指针,以避免重复元素。
-
预计算:
- 由于 的最大值是 ,可以预先计算前 个元素,然后直接查询。
实现步骤
-
初始化:
- 定义数组 存储序列,初始时 。
- 初始化指针 和 。
-
生成序列:
- 从 开始遍历到 :
- 计算候选值 和 。
- 选择较小的候选值作为 。
- 如果 ,则移动 。
- 如果 ,则移动 。
- 从 开始遍历到 :
-
处理查询:
- 对于每个输入的 ,直接输出 。
代码
#include <iostream> #include <algorithm> int d[10000005]; // 存储有序集合元素 int main() { d[1] = 1; // 初始化第一个元素 int mul2 = 1; // 指向下一个可通过2x+1生成的元素位置 int mul3 = 1; // 指向下一个可通过3x+1生成的元素位置 for (int i = 2; i <= 10000000; ++i) { // 计算两个候选值 int candidate2 = d[mul2] * 2 + 1; int candidate3 = d[mul3] * 3 + 1; // 选择较小的作为当前元素 d[i] = std::min(candidate2, candidate3); // 移动生成当前元素的指针 if (d[i] == candidate3) ++mul3; if (d[i] == candidate2) ++mul2; } // 处理查询 int n; while (std::cin >> n) { std::cout << d[n] << std::endl; } return 0; }
复杂度分析
- 时间复杂度:
- 预计算前 个元素的时间复杂度是 ,其中 。
- 查询的时间复杂度是 。
- 空间复杂度:
- 需要 的空间存储序列,其中 。
这种方法通过预计算和动态维护指针,高效地生成了有序序列,适用于大规模查询。
- 1
信息
- ID
- 1592
- 时间
- 1000ms
- 内存
- 64MiB
- 难度
- 10
- 标签
- 递交数
- 6
- 已通过
- 1
- 上传者