当前位置:首页 > 比赛题解 > GESP2023年五级小杨的幸运数 从完全平方数到高效查询的完整指南C++实现(洛谷P3929)

GESP2023年五级小杨的幸运数 从完全平方数到高效查询的完整指南C++实现(洛谷P3929)

7小时前比赛题解18

截图未命名.jpg GESP2023年五级小杨的幸运数 从完全平方数到高效查询的完整指南C++实现(洛谷P3929) GESP2023 五级考试 小杨的幸运数 完全平方数 素数筛法 哈希集合 算法优化 C++实现 洛谷P3929 幸运化处理 第1张

一、题目分析

1.根据题目要求,我们需要处理两种操作:

  1. 判断一个数是否是幸运数(大于等于a的完全平方数或其倍数)

  2. 如果不是幸运数,则进行"幸运化"处理(找到比它大的最小幸运数)

2.解题思路:

  1. ‌预生成幸运数‌:提前计算所有可能的幸运数

  2. ‌高效查询‌:使用哈希集合存储幸运数以实现O(1)查询

  3. 幸运化处理‌:线性搜索比x大的最小幸运数


二、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为到下一个幸运数的距离



原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。