GESP2023年五级小杨的幸运数 从完全平方数到高效查询的完整指南C++实现(洛谷P3929)
一、题目分析
1.根据题目要求,我们需要处理两种操作:
判断一个数是否是幸运数(大于等于a的完全平方数或其倍数)
如果不是幸运数,则进行"幸运化"处理(找到比它大的最小幸运数)
2.解题思路:
二、C++代码实现
#include <iostream> #include <vector> #include <cmath> #include <unordered_set> using namespACe std; // 预先生成所有超级幸运数(≥a的完全平方数)和幸运数(超级幸运数的倍数) unordered_set<int> generateLuckyNumbers(int a, int max_x) { unordered_set<int> lucky_numbers; // 生成超级幸运数(≥a的完全平方数) for (int i = ceil(sqrt(a)); i * i <= max_x; i++) { int super_lucky = i * i; lucky_numbers.insert(super_lucky); // 生成该超级幸运数的所有倍数(幸运数) for (int j = 2; super_lucky * j <= max_x; j++) { lucky_numbers.insert(super_lucky * j); } } return lucky_numbers; } // 幸运化处理:找到比x大的最小幸运数 int makeLucky(int x, const unordered_set<int>& lucky_numbers) { while (true) { if (lucky_numbers.count(x)) return x; x++; } } int main() { int a, N; cin >> a >> N; // 读取所有查询数字,找出最大值以确定生成幸运数的范围 vector<int> queries(N); int max_x = 0; for (int i = 0; i < N; i++) { cin >> queries[i]; if (queries[i] > max_x) max_x = queries[i]; } // 生成幸运数集合(包含所有可能的幸运数,直到最大查询值) unordered_set<int> lucky_numbers = generateLuckyNumbers(a, max_x + 1000); // 额外缓冲 // 处理每个查询 for (int x : queries) { if (lucky_numbers.count(x)) { cout << "lucky" << endl; } else { cout << makeLucky(x, lucky_numbers) << endl; } } return 0; }
三、详细讲解
1. 幸运数生成
我们首先生成所有超级幸运数(≥a的完全平方数),然后生成它们的倍数:
unordered_set<int> generateLuckyNumbers(int a, int max_x) { unordered_set<int> lucky_numbers; // 生成超级幸运数 for (int i = ceil(sqrt(a)); i * i <= max_x; i++) { int super_lucky = i * i; lucky_numbers.insert(super_lucky); // 生成倍数 for (int j = 2; super_lucky * j <= max_x; j++) { lucky_numbers.insert(super_lucky * j); } } return lucky_numbers; }
2. 幸运数判断
使用哈希集合的count方法快速判断:
if (lucky_numbers.count(x)) { cout << "lucky" << endl; }
3. 幸运化处理
从x+1开始逐个检查,直到找到第一个幸运数:
int makeLucky(int x, const unordered_set<int>& lucky_numbers) { while (true) { if (lucky_numbers.count(x)) return x; x++; } }
四、复杂度分析
幸运数生成:O(k log k),k为幸运数数量
幸运数判断:O(1)
幸运化处理:平均O(m),m为到下一个幸运数的距离
原创内容 转载请注明出处