最小质因数 == 最大质因数,不等式秒了!

起因:

  在洛谷做题遇到了这道题~

  一看咿呀,又是道数学题~

  首先我们要了解一下,什么是质数?

  我记得好像有年高考题的前几题好像考了这玩意来着,质数的概念好像在小学学过,上了初中后基本都没有用过了~

  质数就是素数,我们以前应该写过一个程序叫判断某个范围的数里面有多少个素数,其实在这里我们就已经了解过质数的概念了~

  以下是GPT回答的参考:

  质数和素数在数学上指的是同一个概念,两者都是只能被1和它本身整除的正整数,而且大于1。在数学文献中,通常使用“素数”这个词,特别是在欧洲和北美地区,而“质数”则更多地在亚洲和拉丁美洲使用。不过,这两个词指的是完全相同的概念。

  例如,2、3、5、7、11、13、17等都是质数(或素数),因为它们除了1和它们自身以外,没有其他的因数。相对的,像4、6、8、9、10等就不是质数(或素数),因为它们除了1和它们自身以外,还有其他的因数。

  OK,已经知道概念了,因为题目中称呼这种数为质数,我们为统一命名,后文中使用质数来称呼这种数,让我们来看看题~

  已知两个质数的乘积,求其中一个最大的质数,好像并不是很难,如果是用常规的思路的话,用判断质数的那个思路就可以解决掉这道题,前提是不限时~

  于是我第一次提交的代码是这样的~

  第一次提交的代码:

#include<iostream>
#include <iomanip>
#include<climits>

using namespace std;

int main()
{
	int a[10];
	int n, count = 0;
	cin >> n;
	int fact = n;

	for (int i = 2; i < n; i++) {
		if (fact % i == 0)
			a[count++] = i;
	}

	cout << a[count - 1] << endl;
	return 0;
}

  使用一个数组来存储所有可能被 n 整除的数,在数组中的数肯定都是 n 的因数,所以最后一个数组空间中存储的就是最大的质因数~

  理想很丰满,现实很骨感,果不其然超时了 T^T

  第一次提交的结果:

 想想有没有什么可以提高速度的方法?

 实际上,在判断某个数是否为质数时,只需要枚举到这个数开平方后的数(向下取整)就行了~

  为什么质数只需要枚举到这个数开平方后呢?

  首先,我们知道如果一个数 n 不是质数,那么它一定可以被表示为两个较小的正整数相乘,即 n = a * b

现在假设 a 和 b 都大于 sqrt(n)。那么我们有:
a * b = n
a > sqrt(n)
b > sqrt(n)

  从上面的不等式可以看出,a 和 b 都必须大于 sqrt(n)。但是,如果 a 和 b 都大于 sqrt(n),那么它们的乘积 a * b 一定大于 n~

  这就意味着,如果一个数 n 不是质数,那么它一定可以被表示为两个较小的正整数相乘,其中至少有一个数小于或等于 sqrt(n)~

  因此,我们只需要检查 2 到 sqrt(n) 之间的所有整数,就可以确定 n 是否为质数。如果找到任何一个能被 n 整除的数,那么 n 就不是质数。如果在这个范围内没有找到任何能被 n 整除的数,那么 n 就是质数~

  这种方法的时间复杂度是 O(√n),相比于逐一检查 2 到 n-1 之间的所有整数,效率要高得多。这就是为什么判断质数只需要列举到 i <= sqrt(n) 就够了的原因~

  但是这道题我们无法直接使用这种方法,题目中明确说了这个数是两个质数的乘积,所以这个数一定不是质数,如果使用我们上述说到的方法只会求到最小的质因数

  提交就是一片全红,因为我们只求得了最小的质因数,而不是最大的质因数  -_-

  使用上述方法的代码:

#include<iostream>
#include <iomanip>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int a[10];
	int n, count = 0;
	cin >> n;
	int fact = n;

	for (int i = 2; i <= sqrt(n); i++) {
		if (fact % i == 0)
			a[count++] = i;
	}

	cout << a[count - 1] << endl;
	return 0;
}

 使用上述方法的结果:

 

  但是我们可以借助这种思路,先卖个关子~  ^v^

  既然不能取到sqrt(n),那我扩大一些范围总行了吧~

  第二次提交的代码:

#include<iostream>
#include <iomanip>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int a[10];
	int n, count = 0;
	cin >> n;
	int fact = n;

	for (int i = 2; i < sqrt(n)*2+1; i++) {
		if (fact % i == 0)
			a[count++] = i;
	}

	cout << a[count - 1] << endl;
	return 0;
}

   第二次提交的结果:

  先开方,然后再对平方后的数进行扩大,这样做会有错误,因为会有一些边界条件未考虑到,比如如果数是6(2 * 3)的话,枚举到2就没了,结果肯定是错误的~

  那对sqrt(n)取整试试?

  第二次改进后的代码:

#include<iostream>
#include <iomanip>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int a[10];
	int n, count = 0;
	cin >> n;
	int fact = n;

	for (int i = 2; i <= sqrt(n)*2+1; i++) {
		if (fact % i == 0)
			a[count++] = i;
	}

	cout << a[count - 1] << endl;
	return 0;
}

  第二次改进后的结果:

  可以看到还是有问题,我们的取值范围是不对的,取值范围太小了~

  那我们把取值范围扩大一点试试呢?

  第三次提交的代码:

#include<iostream>
#include <iomanip>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int a[10];
	int n, count = 0;
	cin >> n;
	int fact = n;
	int res = 1;

	for (int i = 2; i < n/2; i++) {
		if (fact % i == 0) {
			a[count++] = i;
			res *= i;
			if (res == n)
				break;
		}
			
	}

	cout << a[count - 1] << endl;
	return 0;
}

  在这种思路中,我们扩大了搜索的范围,同时我们增加了一个判断条件:如果发现这个数的质数了,就用一个res(初始为1)相乘,如果res == n了,说明我们已经找到了这个数的最大质因数~

   第三次提交的结果:

 再扩大一下搜索范围试试?

  第三次改进后的代码:

#include<iostream>
#include <iomanip>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int a[100];
	int n, count = 0;
	cin >> n;
	int fact = n;
	int res = 1;

	for (int i = 2; i <= n/3; i++) {
		if (fact % i == 0) {
			a[count++] = i;
			res *= i;
			if (res == n)
				break;
		}
			
	}

	cout << a[count - 1] << endl;
	return 0;
}

第三次改进后的结果:

  可以看到搜索范围还是有问题的~

  大脑.exe已停止运行~

  感觉身体被掏空~

  又冥思苦想10分钟后,还是AC不掉这道题,没办法,看看大佬的题解吧,弱鸡瑟瑟发抖 T^T

  第四次提交的代码:

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    int n;                                 // 读取一个整数 n
    cin >> n;                               
    int largest_prime = 1;                 // 初始化 largest_prime 为 1

    for (int i = 2; i <= sqrt(n); i++) {    // 从 2 开始遍历到 sqrt(n) 之间的整数
        if (n % i == 0) {                   // 如果 n 能被 i 整除
            while (n % i == 0) {            // 不断地将 n 除以 i,直到 n 不能被 i 整除为止
                n /= i;
            }
            largest_prime = i;             // 更新 largest_prime 为当前的 i
        }
    }

    if (n > 1) {                           // 如果 n 大于 1,说明 n 本身就是一个素数
        largest_prime = n;                 // 将其赋值给 largest_prime
    }

    cout << largest_prime << endl;         // 输出 largest_prime
    return 0;
}

  第四次提交的结果:

  是不是有点疑惑?为啥枚举到sqrt(n) ,就可以得出正确结果了呢?之前不是直接错了吗?

  这是因为在前面我们说过,这种方法只能找到最小的质因数,而不能找到最大的质因数,但是题目中明确的告诉我们这是两个质数相乘,所以不用再次判断这个数是否为质数,因此只要找到小的那个质数就可以直接通过相除找到最大的那个质因数~

以下是我当天AC这道题后写下的一些解释:

1.为什么可以直接用n除以较小的那一个质数就可以得到较大的那一个质数?
  质数本来就不可能再被分解,5和7不能被除它以外的数整除,所以5*7=35的两个因子只可能是5和7,不可能是其他因子,故两个质数的乘积分解也会是这两个质数,中间不可能会出现其他结果

2.为什么要枚举到<=sqrt?
  因为两个质数相乘的极端情况就是两个质数相等,比如5*5=25,此时需要在for循环里枚举到5
其他情况肯定就是一个质数大,另一个质数小,但是从for循环开始肯定是先枚举到较小的那一个质数,所以通过质数相乘原理就可以直接得出那一个较大的质数

什么,你跟我说你还不懂?那来看看我优化后的代码吧~

第四次改进后的代码:

#include<iostream>        // 包含输入输出流库
#include<cmath>           // 包含数学运算库

using namespace std;

int main()
{
    int n;                                 // 声明整数变量 n,用于存储输入的正整数
    cin >> n;                              // 输入正整数 n

    for (int i = 2; i <= sqrt(n); i++) {   // 从 2 开始迭代直到 sqrt(n)
        if (n % i == 0) {                  // 如果 n 能被 i 整除
            n /= i;
        }                    
    }

    cout << n << endl;                     // 输出最大质数
    return 0;
}

第四次改进后的结果:

 可以看到,只要我们找到了最小的那个质因数,通过相除就可以直接找到最大的那个质因数,连while循环都不用,这道题就是一道纯纯的数学题~

又用了一坤时才写完,以后得提高一下水文(划掉)的速度了啊~

如果您觉得这篇文章对您有帮助的话,那不妨点个赞或者收藏呗,谢谢您~

如果您觉得我的文章有问题,请您私信我,我看到后就会及时改正,谢谢您!

感谢您的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/503156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

error lsof 0.1 does not meet the minimal requirement

很多小伙伴在linux虚拟机中采用Centos 7镜像安装TitanIDE时&#xff0c;会报错如下信息 error lsof 0.1 does not meet the minimal requirement 这是因为lsof依赖版本较低&#xff0c;只需要在命令行输入 sudo yum install lsof 按下回车以后&#xff0c;命令行会弹出提示命令…

C语言例1-7:以下程序段中执行循环的次数是

代码如下&#xff1a; x-2; do { xx*x; } while(!x); 执行循环次数是&#xff1a;1 先执行后判断 代码如下&#xff1a; #include<stdio.h> int main(void) {int x;x-2;do{ xx*x; printf("\n");printf("x %d\n",x);}while(!x);return 0; } 结果…

Linux - 第三节

改变用户类型 su 仅单纯的进行身份变化 依旧处于普通用户里面 su - 进行重新登录更改身份 退出用exit / ctrld su 用户名 改成成其他身份 对一条命令进行提权 sudo command r:可读 w:可写 x:可执行 -:对应的权限位置&#xff0c;没有权限 去掉所有权限 chmod u…

2024 ccfcsp认证打卡【汇总】

202312-1 仓库规划 202312-2 因子化简 202312-3 树上搜索 202309-1 坐标变换&#xff08;其一&#xff09; 202309-2 坐标变换&#xff08;其二&#xff09; 202305-1 重复局面 202305-2 矩阵运算 202303-1 田地丈量 202303-2 垦田计划 202212-1 现值计算 202212-2 训练计划 20…

Redis实战篇-利用逻辑过期解决缓存击穿问题

实战篇Redis 3.0 、利用逻辑过期解决缓存击穿问题 需求&#xff1a;修改根据id查询商铺的业务&#xff0c;基于逻辑过期方式来解决缓存击穿问题 思路分析&#xff1a;当用户开始查询redis时&#xff0c;判断是否命中&#xff0c;如果没有命中则直接返回空数据&#xff0c;不…

打工人神器! Raccoon 代码小浣熊

继这三个之后&#xff0c;今天又来了一个 [ Raccoon代码小浣熊 ] 核心精要与产品特点 全面支持多种编程语言和IDE&#xff1a;「代码小浣熊」支持超过90种主流编程语言&#xff0c;包括但不限于Python、Java、JavaScript、C、Go和SQL等。同时&#xff0c;它集成了市面上主流的…

基于jsp+mysql+Spring+hibernate+的SSH在线学习交流论坛平台

基于jspmysqlSpringhibernate的SSH在线学习交流论坛平台 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末…

Unreal的Quixel Bridge下载速度过慢、下载失败

从Quixel Bridge下载MetaHuman模型&#xff0c;速度非常慢&#xff0c;而且经常下载失败&#xff0c;从头下载。 可以从Quixel Bridge的右上角我的图标->Support->Show Logs打开日志目录 downloaded-assets目录下为下载的资源 bridge-plugin.log文件记录了下载URL和下载…

java(1)之环境部署

1、下载安装包 直接百度java 点击这个就可以&#xff0c;进去之后下载&#xff0c;根据自身情况&#xff0c;window就下Windows版本的记得下那个jdk别下别的&#xff08;用不了&#xff09;&#xff0c;然后下一个编译器可以是idea可以是eclipse都可以 2、环境搭建 分为两步…

如何确保实物档案的安全

确保实物档案的安全有以下几个关键点&#xff1a; 1. 建立完善的安全措施&#xff1a;为实物档案建立专门的存储区域&#xff0c;控制进出口&#xff0c;限制访问权限&#xff0c;并使用安全锁和监控设备等物理安保措施。 2. 规范档案管理制度&#xff1a;建立档案管理制度&…

算法学习——LeetCode力扣动态规划篇10

算法学习——LeetCode力扣动态规划篇10 583. 两个字符串的删除操作 583. 两个字符串的删除操作 - 力扣&#xff08;LeetCode&#xff09; 描述 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个…

使用 golang 以及 Gin 框架,将上传的图片在不保存至本地的情况下添加水印,并上传至阿里云 OSS

正如标题所述&#xff0c;使用golang对上传图片添加水印&#xff0c;以及将图片上传到阿里云OSS&#xff0c;网上一搜索&#xff0c;便有你想要的结果了&#xff0c;可是&#xff0c;他们却先将上传图片添加水印后保存在本地&#xff0c;而后再将添加了水印的图片上传到阿里云O…

【个人笔记】python界面美化

目录 标题栏美化 样例展示 代码 配套鼠标移动 完整展示 标题栏美化 样例展示 代码 import tkinter as tk from tkinter import ttk from PIL import Image, ImageTk import subprocess import sysdef open_buy_quantity():window.destroy()subprocess.run(["p…

网际协议 - IP

文章目录 目录 文章目录 前言 1 . 网际协议IP 1.1 网络层和数据链路层的关系 2. IP基础知识 2.1 什么是IP地址? 2.2 路由控制 3. IP地址基础知识 3.1 IP地址定义 3.2 IP地址组成 3.3 IP地址分类 3.4 子网掩码 IP地址分类导致浪费? 子网与子网掩码 3.5 CIDR与…

记录个人学习golang路线(如何学习golang,如何转golang)

最近好久没更&#xff0c;在看兔兔的博客&#xff0c;学习golang&#xff0c;兔兔的文章&#xff0c;有一定的编程经验 && 初学golang者&#xff0c;一定要看&#xff0c;如果是其他语言转golang&#xff0c;那就必须要看了&#xff0c;可以帮助你了解golang的语法&…

BC40056 Imports“SolidWorks.Interop.swconst”中指定的命名空间或类型不包含任何公共成员

BC40056 Imports“SolidWorks.Interop.swconst”中指定的命名空间或类型不包含任何公共成员&#xff0c;或者找不到该命名空间或类型。 问题描述原因分析 解决办法 ) 问题描述 严重性 代码 说明 项目 文件 行 警告 BC40056 Imports“SolidWorks.Interop.swconst”中指定的命名…

单链表就地逆置

算法思想&#xff1a;构建一个带头结点的单链表L&#xff0c;然后访问链表中的每一个数据结点&#xff0c;将访问到的数据结点依此插入到L的头节点之后。 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef s…

ElasticSearch开发指北和场景题分析

前言 本篇是ES系列的第二篇&#xff0c;继上次的理论篇ElasticSearch理论体系构建后&#xff0c;带来了实战篇。实战篇来自于我对常见操作以及场景的分析总结&#xff0c;详细到每个步骤和理由&#xff0c;下一篇将是性能优化篇。 常用操作 以下操作均使用ES的API进行展示&a…

金融投贷通--功能测试分析与设计

金融投贷通功能测试分析与设计 测试点分析借款业务测试点投资业务测试点 测试用例借款业务测试用例投资业务测试用例 缺陷面试题 测试报告 测试点分析 借款业务测试点 投资业务测试点 测试用例 借款业务测试用例 借款成功&#xff08;主业务&#xff09;、借款成功&#xff…

Figma:如何在数据库规模四年增长近100倍的挑战中“活”下来?

在当今数字化飞速发展的时代&#xff0c;大数据的崛起已成为各行业不可或缺的重要驱动力。然而&#xff0c;随着数据量的激增&#xff0c;许多企业面临着巨大的挑战&#xff0c;尤其是在数据库管理和维护方面。Figma作为一家专注于设计协作领域的领先企业&#xff0c;在过去的四…