当前位置: 首页 > article >正文

P8795 [蓝桥杯 2022 国 A] 选素数

题目描述:

小蓝有一个数 x,每次操作小蓝会选择一个小于 x 的素数 p,然后在 x 成为 p 的倍数前不断将 x 加 1,(如果 x 一开始就是 p 的倍数则 x 不变)。

小乔看到了小蓝进行了 2 次上述操作后得到的结果 n,他想知道 x 在一开始是多少。如果有多种可能,他想知道 x 一开始最小可以是多少,而如果不存在任何解,说明小乔看错了,此时请输出 −1。

输入格式

输入一行包含一个整数 n,表示经过两次操作后 x 的值。

输出格式

输出一行包含一个整数表示 x 的初始值。如果有多个解,输出最小的。如果不存在解,请输出 −1。

输入输出样例

输入 #1

22

输出 #1

8

说明/提示

【评测用例规模与约定】

  • 对于 60% 的评测用例,1≤n≤5000;
  • 对于所有评测用例,1≤n≤1e6。

蓝桥杯 2022 国赛 A 组 G 题。

解题思路:

我们先将题目简化一下,假设只求一次操作数后最小值。先拆解一下题目。首先这个输入数n是某个质数的k倍,那么这个初始数一定是在这个质数的k倍和(k-1)倍之间,因为若小于质数的(k-1)倍,在初始数不断++的过程中就会提前终止。同时题目又要求这个数为最小值,那么这个数就是输入数n的最大质因数+1。(我们暂且将其定义为x)

同理可得,我们通过第一次的计算算出了x,那么第二次的要找的操作数就在x和n之间,我们只需要依次算出他们的最大质因数,然后通过(操作数-最大质因数+1)的方法求得最小初始值。

举个例子如果说输入的数是39,那么它的最大质因数就是13,将39-13+1后得到27,那么第二次的操作数就在27,28,30,32,33,34,35,36,38之间产生。通过上面的方法我们一次对这些数进行运算,如法炮制,算出他们的最小初始值,然后进行比较得到整个数组的最小初始值,就能获得最终的最小操作数。上述的结果得到34的最大质因数17,34-17+1得到18,那么18就是初始值。

下面我们进行代码书写。

样例代码:

#include<iostream>
using namespace std;

const int MAXN = 1000001;
int m, t;                    // m:输入数值,t:质数计数
bool isprime[MAXN];
int prime[MAXN];             // p存储质数
int p[MAXN];                 // 存储某个数最大的质因数
int ans = 1e9;               // 用来存储最小的符合条件的值

// f函数用于计算给定的数字m的值,返回结果为 (m - p[m] + 1)
int f(int m)
{
    if (isprime[m] == true)   // 如果m是质数
    {
        return 1e9;           // 返回一个非常大的值
    }
    return (m - p[m] + 1);     // 返回 (m 减去最大质因数 p[m] + 1)
}

// 线性筛法(欧拉筛法)
// 用于筛出 1 到 m 之间的所有质数
void Linear_sieve()
{
    for (int i = 2; i <= m; i++)   // 从 2 开始遍历到 m
    {
        isprime[i] = true;         // 假设每个数都是质数
    }

    for (int i = 2; i <= m; i++)   // 遍历每个数字
    {
        if (isprime[i])            // 如果当前数是质数
        {
            t++;                   // 质数计数器加 1
            prime[t] = p[i] = i;   // prime[t] 存储当前质数 i,p[i] 存储 i
        }
        // 从当前质数 i 开始遍历后续数
        for (int j = 1; j <= t && i * prime[j] <= m; j++)
        {
            p[i * prime[j]] = max(p[i], prime[j]);  // 更新 i * prime[j] 的最大质因数
            isprime[i * prime[j]] = false;           // 将 i * prime[j] 标记为合数
            if (i % prime[j] == 0)  // 为了避免重复计算,减少多余的操作
            {
                break;  // 如果 i 已经能被 prime[j] 整除,跳出循环,避免重复标记
            }
        }
    }
}

int main()
{
    cin >> m;
    Linear_sieve();      // 通过线性筛法生成质数和更新其他数组

    // 下面的循环是为了找出最小的符合条件的数
    for (int i = f(m); i <= m; i++) // 循环从 f(m) 到 m
    {
        ans = min(ans, f(i));   // 计算 f(i),并更新 ans 为最小值
    }

    // 如果 ans 被更新过,说明找到了符合条件的结果
    if (ans != 1e9)
    {
        cout << ans << endl;  // 输出最小的符合条件的值
    }
    else
    {
        cout << "-1" << endl;  // 没有找到符合条件的值,输出 -1
    }

    return 0;
}

代码解读:

我们首先遍历2到m的数,将它们假设为质数(true),那么后序我们只需要排除掉不是质数的数(false)。Linear_sieve()是欧拉筛法,用于筛选出质数,并且将每个数的最大质因数保存在p数组中。


http://www.kler.cn/a/442051.html

相关文章:

  • Reactive StreamsReactor Core
  • Amazon MSK 开启 Public 访问 SASL 配置的方法
  • 人工智能之数学基础:线性代数中的线性相关和线性无关
  • 【Web】2025西湖论剑·中国杭州网络安全安全技能大赛题解(全)
  • leetcode707-设计链表
  • Solidity01 Solidity极简入门
  • [java]网络编程
  • 使用vitejs搭配vue.js,快速构建简单的网站案例展示Demo
  • Java基础夯实——2.6 Java中锁
  • STM32-笔记3-驱动蜂鸣器
  • 警告 torch.nn.utils.weight_norm is deprecate 的参考解决方法
  • Scala 的迭代器
  • 基于遗传优化SVM支持向量机的数据分类算法matlab仿真,SVM通过编程实现,不使用工具箱
  • VMware Workstation Pro 17 与 虚拟机 ——【安装操作】
  • NoSQL数据库介绍与分类
  • 引言和相关工作的区别
  • AOP实现操作日志记录+SQL优化器升级
  • NFT市场回暖:蓝筹项目成为复苏主力,空投潮助推价格上涨
  • Android 13 Aosp SystemServer功能裁剪(PackageManager.hasSystemFeature())
  • Jenkins搭建并与Harbor集成上传镜像
  • 如何查看K8S集群中service和pod定义的网段范围
  • 备战美赛!2025美赛数学建模C题模拟预测!用于大家练手模拟!
  • Python之公共操作篇
  • AirSim 无人机不同视角采集不同场景的图片
  • SEO短视频矩阵系统源码开发概述
  • 域名历史是什么?怎么进行域名历史查询?