首页 > 其他分享 >【洛谷】P1217 [USACO1.5] 回文质数(AC详解)

【洛谷】P1217 [USACO1.5] 回文质数(AC详解)

时间:2024-12-10 23:57:49浏览次数:6  
标签:AC 判断 洛谷 奇数 int 质数 偶数 回文


#include <iostream>  //引入输入输出流头文件,用于实现标准输入输出操作,例如使用cin和cout
#include <cmath>    //引入数学函数库头文件,主要用于调用sqrt函数来求平方根,辅助判断质数
using namespace std;

//函数声明,用于判断一个整数是否为质数,接收一个整数参数,返回布尔值表示是否为质数
bool isPri(int x);  
//函数声明,用于判断一个整数是否为回文数,接收一个整数参数,返回布尔值表示是否为回文数
bool isPal(int x);  

int main()
{
    int a, b;
    //从标准输入读取两个整数,分别赋值给变量a和b,这两个整数将确定后续查找的区间范围
    cin >> a >> b;  

    //循环遍历从a到b(包含a和b)的每一个整数i
    for (int i = a; i <= b; i++)  
    {
        //通过按位与操作判断i是否为奇数,i & 1的结果为1则表示i是奇数,为0则表示是偶数
        //也可以直白点是if (i % 2 != 0),时间差不多,是可以AC的
        if (i & 1)  
        {
            //调用isPal函数判断i是否为回文数,如果是回文数则进入下面的判断
            if (isPal(i))  
            {
                //调用isPri函数判断i是否为质数,如果是质数则输出该整数,每个整数占一行
                if (isPri(i))  
                    cout << i << "\n";  
            }
        }
    }
    return 0;
}

//定义函数isPri,用于判断传入的整数x是否为质数
bool isPri(int x)
{
    //如果x能被2整除(即x是偶数且不为2时),直接返回0,表示x不是质数
    if (x % 2 == 0)  
        return 0;

    int i;
    //从2开始到sqrt(x)遍历,尝试判断x能否被这些数整除,以此来确定x是否为质数
    for (i = 2; i <= sqrt(x); i++)  
    {
        //如果x能被i整除,说明x不是质数,直接返回0
        if (x % i == 0)  
            return 0;
    }
//如果循环结束后i大于sqrt(x),意味着在2到sqrt(x)范围内没有能整除x的数,所以x是质数,返回1
    if (i > sqrt(x))  
        return 1;
}

//定义函数isPal,用于判断传入的整数x是否为回文数
bool isPal(int x)
{
    int ori = x;  //将传入的整数x保存到ori变量中,用于后续和反转后的数字进行对比
    int re = 0;    //用于存储x反转后的数字,初始化为0

    //当x大于0时,通过循环不断取出x的最低位数字添加到re中,实现数字的反转
    while (x > 0)  
    
    //取出x的最低位数字(通过取余操作),添加到re中,每次添加前先将re乘以10,实现数字位权的递增
        re = re * 10 + x % 10;  
        //将x缩小10倍(通过整除操作),去掉已经处理过的最低位数字
        x /= 10;  
    }
    //对比原数字ori和反转后的数字re,如果相等则返回1,表示x是回文数;否则返回0,表示不是回文数
    return ori == re;  
}

此题的最大难点在于范围过大,枚举时间复杂度高,容易TLE,那么优化代码提高效率就是重中之重(当然代码也要兼顾好写...)。这里我主要在三处地方优化代码提高了效率:

1. 在main函数中对奇数的筛选以及判断的技巧

  • 具体代码体现及操作逻辑
    main函数中有如下代码片段:
for (int i = a; i <= b; i++)
{
    if (i & 1)
    {
        if (isPal(i))
        {
            if (isPri(i))
                cout << i << "\n";
        }
    }
}

这里使用了按位与操作符&,通过i & 1来判断i是否为奇数。按位与操作是将两个整数对应的二进制位进行逐位的与运算,数字1的二进制表示为00000001(以一个字节举例,实际在计算机中根据整型的字节数而定,但原理相同),当一个整数i1进行按位与运算时,如果结果为1,就意味着i的最低位二进制位是1,根据二进制的特性,最低位为1的整数就是奇数,反之则为偶数。

  • 效率提升方面的详细解释
    在整个程序要从区间[a, b]中找出满足特定条件的数时,由于最终要求的数需要同时具备奇数、回文数以及质数这三个属性,提前把偶数排除掉能避免很多不必要的后续操作。从概率角度来看,在整数的分布中,奇数和偶数大致各占一半(不考虑特殊边界情况等)。如果不进行这个提前筛选,对于区间内的每一个数,无论奇偶,都要依次调用isPal函数去判断是否为回文数,再调用isPri函数去判断是否为质数。以一个较大的区间,比如[1, 10000]为例,总共要处理10000个数,如果不筛选奇数,那么就要执行10000次回文数判断和10000次质数判断相关的函数调用及内部操作;而通过i & 1筛选出奇数后,理论上只需要对大约5000个奇数进行后续的回文数和质数判断操作,大大减少了函数调用次数以及相应的计算量,从而显著提高了程序整体的运行效率,尤其在区间范围越大、数字越多时,这种效率提升效果就越明显。 

判断时采用 

 if (isPal(i))
        {
            if (isPri(i))
                cout << i << "\n";
        }

 而不采用

 if (isPal(i) && isPri(i))
     cout << i << "\n";

 原因是先判断是否为回文数再判断是否为质数也可以减少计算量哦~

2. 在isPri函数中对偶数的预处理及除数选取优化

  • 对偶数的预处理
    isPri函数中,代码开头部分如下:
bool isPri(int x)
{
    if (x % 2 == 0)
        return 0;
    //后续代码省略(循环等相关代码)
}

这里通过x % 2 == 0来判断x是否为偶数。取余运算(%)是计算一个数除以另一个数后的余数,当x除以2余数为0时,就表明x能被2整除,也就是x是偶数。而根据质数的定义,除了2这个特殊的质数外,其他所有偶数都不可能是质数,因为质数是除了1和它自身外,不能被其他自然数整除的数,偶数都至少能被2整除(除了本身就是2的情况)。

例如,对于数字6,6 % 2 = 0,直接就能判断它不是质数,无需再进行后续复杂的判断操作;同样对于1012等偶数,都可以通过这一步快速得出不是质数的结论,避免进入后面的循环去进一步尝试用其他数整除它来判断是否为质数,节省了大量不必要的计算资源和时间开销。特别是在处理大量数字的场景下,比如要判断1100000之间所有数字是否为质数,其中偶数占了一半左右,如果没有这个提前判断偶数的步骤,循环部分的代码就要对这些偶数也逐个进行多余的判断操作,而有了这个判断后,就可以快速跳过这些偶数的相关流程,直接处理奇数情况,极大地提高了整体判断质数的效率。

  • 除数选取优化(只使用奇数作为除数)
    isPri函数的循环部分,代码如下:
for (i = 3; i <= sqrt(x); i += 2)
{
    if (x % i == 0)
        return 0;
}

这里将循环的起始值设为3,步长设为2,使得循环中使用的除数i都是奇数。其背后的数学原理基于质数的因数特性。对于一个大于1的整数x,如果它不是质数,即它可以分解成两个因数相乘的形式(假设为ab,且a <= b),根据数学推导,必然存在a <= sqrt(x)b >= sqrt(x)这样的关系(可以通过简单的数学不等式推导得出,若x = a * b,两边同时开平方可得sqrt(x) = sqrt(a * b),由于a <= b,所以a <= sqrt(x))。

而且除了2以外,其他偶数都可以表示为2乘以另一个整数,所以在判断一个数是否能被除自身和1以外的数整除时,只需要考虑奇数作为可能的因数即可。例如,对于数字25,其因数有1525,在判断它是否为质数时,我们只需要用奇数去尝试整除它就行,从3开始(因为已经提前处理了偶数情况且1和它本身不需要判断),步长为2,也就是尝试用35(刚好能整除,此时就可以判断它不是质数了)等奇数去判断,而不需要用468等偶数去尝试整除它,因为这些偶数不可能是它除了自身和1以外的因数。

从效率角度来看,在判断一个较大的数是否为质数时,比如123457,常规的做法如果是从2开始逐个遍历到sqrt(123457),会有大量的偶数作为除数参与判断,而这些偶数除了2本身外是不可能成为其因数的,属于无效的判断操作。通过只使用奇数作为除数,大致能减少一半的循环次数,显著降低了计算量,让判断质数这个操作在面对较大数字或者大量数字判断时,执行速度更快,从而提升了整个程序的运行效率。

感觉有帮助的小伙伴不妨点点赞和收藏~

标签:AC,判断,洛谷,奇数,int,质数,偶数,回文
From: https://blog.csdn.net/2401_86982397/article/details/144308466

相关文章

  • autofac aop扩展
    classProgram{    staticvoidMain(string[]args)    {        //创建一个容器        ContainerBuilderbuilder=newContainerBuilder();       //注册UserService        builder.RegisterType<UserService>().As<IUser......
  • Windows Image Acquisition (WIA) 服务是 Windows 操作系统中的一个关键服务,主要用于
    WindowsImageAcquisition(WIA)服务是Windows操作系统中的一个关键服务,主要用于扫描仪、数码相机等设备的图像采集和管理。它为这些设备提供必要的软件接口,使得用户可以通过标准应用程序(如Windows照片查看器、扫描仪应用等)来获取图像数据。1. WIA服务概述服务名称: St......
  • React-Weather-App
    (2024/12/0814:20--2024/12/0816:48) GitHub-hamza-mirza/react-weather-app:SourcecodeformyReactweatherapptutorial.https://www.youtube.com/watch?v=204C9yNeOYI......
  • 解决 Mac(M1/M2)芯片,使用node 14版本
    前言nvm在安装Node.jsv14.21.3时,报错:nvminstall14Downloadingandinstallingnodev14.21.3...Downloadinghttps://nodejs.org/dist/v14.21.3/node-v14.21.3-darwin-arm64.tar.xz...curl:(56)TherequestedURLreturnederror:404Binarydownloadfromhttps:/......
  • 广州大学acm新生赛
       #include<iostream>#include<unordered_map>#include<unordered_set>#include<map>#include<string>#include<vector>#include<algorithm>usingnamespacestd;//定义存储每个队伍的相关数据结构structTeamData{in......
  • Apache DolphinScheduler 限制秒级别的定时调度
    背景ApacheDolphinScheduler定时任务配置采用的7位Crontab表达式,分别对应秒、分、时、月天、月、周天、年。在团队日常开发工作中,工作流的定时调度一般不会细化到秒级别。但历史上出现过因配置的疏忽大意而产生故障时间,如应该配置每分钟执行的工作流被配置长了每秒执行,造......
  • 埃氏筛/线性筛+质数与约数一本通题解
    埃氏筛:筛选\(1...n\)中所有的质数考虑一个质数\(x\),它的\(2x,3x,4x...n/x*x\)都是合数,打上标记即可\(O(NloglogN)\)for(inti=2;i<=n;i++){if(vis[i])continue;p[++cnt]=i;for(intj=i;j<=n/i;j++){vis[i*j]=1;}}线性筛:考虑一个合数......
  • oracle 架构详解
    Oracle数据库是一个复杂且强大的关系型数据库管理系统(RDBMS),广泛应用于企业级应用中。了解Oracle的架构对于数据库管理员(DBA)、开发人员和架构师来说至关重要。以下是Oracle数据库架构的详细解析,涵盖了其主要组成部分、工作原理以及如何优化性能。Oracle数据库Oracle数......
  • Nacos之健康检测
    Nacos服务-领域模型在NacosServer中,服务和配置是一等公民,而在Server侧服务信息的存储采用的是分级存储模型服务(一组功能集的抽象):namespace,group,serviceName标识一个服务实例:服务在具体IP,端口上的提供者应用启动时的注册就是注册某个服务的实例集群:服务之下,实例之......
  • CS-UY 4563 - Introduction to Machine Learning
    FinalProjectCS-UY4563-IntroductiontoMachineLearningOverviewPartnerwithonestudentandselectamachinelearningproblemofyourchoice.Applythemachinelearningtechniquesyou’velearnedduringthecoursetoyourchosenproblem.Present......