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

数学专题3 - 质因数分解

1. 质因数分解

1.1 质因数分解的定义

质因数分解是将一个正整数表示为几个质数的乘积的过程。每个大于1的整数都可以唯一地分解为质数的乘积。

1.2 质因数分解的方法

1.2.1 试除法

试除法是通过逐个试除小于等于该数平方根的质数来寻找质因数的方法。

1.2.1.1天秀的数列挑战

天秀面前有一个长度为 ( n ) 的数列 ( A ),每个元素是正整数。她可以进行多次操作,每次操作选择数列中的一个元素并将其替换为其任意质因数(也可以是它本身)。

现在,天秀想知道,至少需要多少次操作,才能使数列中的所有元素相等。

输入格式

第一行包含一个整数 ( n )(( 1 \leq n \leq 10^5 ))。

第二行包含 ( n ) 个整数,表示数列 ( A ),其中 ( 1 \leq A[i] \leq 10^7 )。

输出格式

输出一个整数,表示最少的操作次数。

样例输入1

3
4 6 8

样例输出1

2

样例解释1

一个可能的操作序列是:( 6 ) 变为 ( 3 ),( 8 ) 变为 ( 4 ),然后 ( 4 ) 和 ( 3 ) 都变为 ( 1 )。

样例输入2

4
10 14 22 35

样例输出2

3

样例解释2

所有数都可以通过至多3次操作变为1,例如 ( 10 ) 变为 ( 5 ),( 14 ) 和 ( 22 ) 变为 ( 11 ),( 35 ) 变为 ( 7 ),最后这些质数都变为 ( 1 )。

样例输入3

2
15 25

样例输出3

1

样例解释3

( 25 ) 可以直接变为 ( 5 ),然后 ( 15 ) 和 ( 5 ) 都变为 ( 5 )。

样例输入4

5
2 4 8 16 32

样例输出4

4

样例解释4

这是2的幂次数列,最优操作是逐步降低每个数的幂次。

样例输入5

3
17 34 51

样例输出5

1

样例解释5

所有数字都可以变为17。

数据范围

  • 对于 30 % 30\% 30% 的数据,( n \leq 100 ),( A[i] \leq 1000 )。
  • 对于 100 % 100\% 100% 的数据,( 1 \leq n \leq 10^5 ),( 1 \leq A[i] \leq 10^7 )。

解题思路

这是一个关于质因数分解的问题。需要高效地对数列中的每个数进行质因数分解,然后找出使所有数相等的最小操作次数。直接的暴力方法由于数据范围很大往往不能通过,需要采用更高效的算法来处理质因数分解,比如使用埃拉托斯特尼筛法或欧拉筛法预处理质数,并快速分解数列中的数。
这里是上述代码的中文注释版本:

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>using namespace std;const int MAXN = 10000000;  // 最大范围设为10^7
vector<int> primes;  // 用于存储所有质数
vector<bool> is_prime(MAXN + 1, true);  // 标记是否为质数// 埃拉托斯特尼筛法
void sieve() {is_prime[0] = is_prime[1] = false;  // 0和1不是质数for (int i = 2; i * i <= MAXN; ++i) {if (is_prime[i]) {primes.push_back(i);for (int j = i * i; j <= MAXN; j += i) {is_prime[j] = false;  // 剔除i的倍数}}}
}// 解决问题的主要函数
int solve(const vector<int>& nums) {map<int, int> factor_count;  // 存储每个质因数出现的次数for (int num : nums) {for (int prime : primes) {if (prime * prime > num) break;  // 超过范围则停止while (num % prime == 0) {  // 除尽所有质因数factor_count[prime]++;num /= prime;}}if (num > 1) factor_count[num]++;  // 处理剩余的大于1的数}int max_operations = 0;  // 最大操作次数for (auto& p : factor_count) {max_operations = max(max_operations, p.second);  // 找出最大频次}return max_operations;
}int main() {int n;cin >> n;  // 输入数列长度vector<int> nums(n);  // 存储数列for (int i = 0; i < n; ++i) {cin >> nums[i];  // 输入数列各元素}sieve();  // 预处理质数cout << solve(nums) << endl;  // 输出最小操作次数return 0;
}

这个程序使用埃拉托斯特尼筛法来预处理质数,并用它们来分解数列中的每个数,同时统计每个质因数出现的次数。最后,计算出使所有数相等所需的最少操作次数。

1.2.1.2 天秀的跑道赛

天秀是一名运动员,她正在参加一个特别的跑道赛。这个赛道有多条跑道,每条跑道的长度不同,运动员需要在每条跑道上跑整数圈才能完成比赛。天秀想要知道,为了在所有跑道上跑相同的总距离,她至少需要跑多少距离。

输入格式

第一行包含一个整数 ( n )(( 1 \leq n \leq 10^3 )),表示跑道的数量。

第二行包含 ( n ) 个整数,每个整数 ( L_i )(( 1 \leq L_i \leq 10^3 ))表示每条跑道的长度(单位:米)。

输出格式

输出一个整数,表示天秀为了在每条跑道上至少跑一圈且总距离相同,至少需要跑的总距离(单位:米)。

样例输入1

3
400 300 600

样例输出1

1200

样例解释1

天秀可以在第一条跑道上跑3圈(1200米),第二条跑道上跑4圈(1200米),第三条跑道上跑2圈(1200米),使得在每条跑道上的跑行距离都是1200米。

样例输入2

2
200 450

样例输出2

1800

样例解释2

天秀可以在第一条跑道上跑9圈(1800米),第二条跑道上跑4圈(1800米),使得在两条跑道上的跑行距离都是1800米。

解题思路

这个问题实际上是在求多个数的最小公倍数,但是我们可以通过模拟的方式来表述这个问题。在赛道长度的背景下,求最小公倍数实际上就是找出可以让天秀在所有跑道上至少跑一圈的最短总距离。

以下是这个问题的C++解答:

#include <iostream>
#include <vector>
using namespace std;// 计算最大公约数
int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;
}// 计算最小公倍数
int lcm(int a, int b) {return a / gcd(a, b) * b;
}int main() {int n;cin >> n;vector<int> tracks(n);for (int i = 0; i < n; ++i) {cin >> tracks[i];}int result = tracks[0];for (int i = 1; i < n; ++i) {result = lcm(result, tracks[i]);}cout << result << endl;return 0;
}

这段代码通过模拟天秀在跑道上跑步的过程,计算她需要跑的最短总距离,实际上就是求解了所有跑道长度的最小公倍数。天秀的跑道赛

天秀是一名运动员,她正在参加一个特别的跑道赛。这个赛道有多条跑道,每条跑道的长度不同,运动员需要在每条跑道上跑整数圈才能完成比赛。天秀想要知道,为了在所有跑道上跑相同的总距离,她至少需要跑多少距离。

输入格式

第一行包含一个整数 ( n )(( 1 \leq n \leq 10^3 )),表示跑道的数量。

第二行包含 ( n ) 个整数,每个整数 ( L_i )(( 1 \leq L_i \leq 10^3 ))表示每条跑道的长度(单位:米)。

输出格式

输出一个整数,表示天秀为了在每条跑道上至少跑一圈且总距离相同,至少需要跑的总距离(单位:米)。

样例输入1

3
400 300 600

样例输出1

1200

样例解释1

天秀可以在第一条跑道上跑3圈(1200米),第二条跑道上跑4圈(1200米),第三条跑道上跑2圈(1200米),使得在每条跑道上的跑行距离都是1200米。

样例输入2

2
200 450

样例输出2

1800

样例解释2

天秀可以在第一条跑道上跑9圈(1800米),第二条跑道上跑4圈(1800米),使得在两条跑道上的跑行距离都是1800米。

解题思路

这个问题实际上是在求多个数的最小公倍数,但是我们可以通过模拟的方式来表述这个问题。在赛道长度的背景下,求最小公倍数实际上就是找出可以让天秀在所有跑道上至少跑一圈的最短总距离。

以下是这个问题的C++解答:

#include <iostream>
#include <vector>
using namespace std;// 计算最大公约数
int gcd(int a, int b) {while (b != 0) {int temp = b;b = a % b;a = temp;}return a;
}// 计算最小公倍数
int lcm(int a, int b) {return a / gcd(a, b) * b;
}int main() {int n;cin >> n;vector<int> tracks(n);for (int i = 0; i < n; ++i) {cin >> tracks[i];}int result = tracks[0];for (int i = 1; i < n; ++i) {result = lcm(result, tracks[i]);}cout << result << endl;return 0;
}

这段代码通过模拟天秀在跑道上跑步的过程,计算她需要跑的最短总距离,实际上就是求解了所有跑道长度的最小公倍数。

1.2.1.3 天秀的数字游戏

天秀在玩一个数字游戏。游戏规则是:给定一个正整数区间 ([L, R]),天秀需要找出这个区间内每个数的质因数分解,并计算出所有这些数的质因数分解中质因数的总数量。

输入格式

输入包含两个整数 ( L ) 和 ( R )(( 1 \leq L \leq R \leq 10^6 ))。

输出格式

输出一个整数,表示区间 ([L, R]) 内所有数的质因数分解中质因数的总数量。

样例输入1

2 5

样例输出1

4

样例解释1

  • 2 的质因数是 2。
  • 3 的质因数是 3。
  • 4 的质因数是 2, 2。
  • 5 的质因数是 5。

所以,质因数的总数量是 4。

样例输入2

6 10

样例输出2

7

样例解释2

  • 6 的质因数是 2, 3。
  • 7 的质因数是 7。
  • 8 的质因数是 2, 2, 2。
  • 9 的质因数是 3, 3。
  • 10 的质因数是 2, 5。

所以,质因数的总数量是 7。

解题思路

对于这个问题,暴力地为区间内每个数进行质因数分解是不现实的,因为当区间很大时,这样做的时间复杂度非常高。可以使用埃拉托斯特尼筛法(Sieve of Eratosthenes)或欧拉筛法来高效地找出所有需要的质数,并进行质因数分解。

以下是采用欧拉筛法的C++解答:

#include <iostream>
#include <vector>using namespace std;const int MAXN = 1000000;
vector<int> primes;
vector<bool> is_prime(MAXN + 1, true);// 欧拉筛法
void eulerSieve(int n) {for (int i = 2; i <= n; ++i) {if (is_prime[i]) {primes.push_back(i);}for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {is_prime[i * primes[j]] = false;if (i % primes[j] == 0) break;}}
}// 计算区间内所有数的质因数总数量
int countPrimeFactors(int L, int R) {eulerSieve(R);int total = 0;for (int i = L; i <= R; ++i) {int n = i;for (int prime : primes) {if (prime * prime > n) break;while (n % prime == 0) {total++;n /= prime;}}if (n > 1) total++;  // n 自身是一个质数}return total;
}int main() {int L, R;cin >> L >> R;cout << countPrimeFactors(L, R) << endl;return 0;
}

这个解法中,eulerSieve 函数使用欧拉筛法生成所有需要的质数,并存储在 primes 数组中。然后 countPrimeFactors 函数计算区间 [L, R] 内每个数的质因数分解中质因数的总数量。这种方法的时间复杂度相对较低,适合处理大范围的数据。

题目:天秀的秘密数字

天秀正在参与一个解密游戏,她需要找到一个特定的秘密数字。这个秘密数字是在一个给定区间 ([L, R]) 内唯一一个满足以下条件的整数:它的质因数分解中恰好有 ( K ) 个不同的质因数。

输入格式

输入包含三个整数 ( L ), ( R ) 和 ( K )(( 1 \leq L \leq R \leq 10^6 ),( 1 \leq K \leq 10 ))。

输出格式

输出一个整数,表示区间 ([L, R]) 内满足条件的秘密数字。如果不存在这样的数字,则输出 -1

样例输入1

2 10 2

样例输出1

6

样例解释1

在区间 ([2, 10]) 内,( 6 = 2 \times 3 ) 有 2 个不同的质因数,满足条件。

样例输入2

10 20 3

样例输出2

30

样例解释2

在区间 ([10, 20]) 内,( 30 = 2 \times 3 \times 5 ) 有 3 个不同的质因数,满足条件。

解题思路

此问题不仅需要质因数分解,还需要确定分解后的质因数数量。由于直接对每个数进行质因数分解效率不高,特别是在大区间处理时,我们可以预先使用筛法,比如埃拉托斯特尼筛法或欧拉筛法,来找出所有质数,并快速计算区间内每个数的质因数数量。

以下是C++解答的基本框架:

#include <iostream>
#include <vector>using namespace std;const int MAXN = 1000000;
vector<int> smallestPrimeFactor(MAXN + 1, 0);// 埃拉托斯特尼筛法初始化最小质因数
void sieve() {for (int i = 2; i <= MAXN; ++i) {if (smallestPrimeFactor[i] == 0) { // i is a primefor (int j = i; j <= MAXN; j += i) {if (smallestPrimeFactor[j] == 0) {smallestPrimeFactor[j] = i;}}}}
}// 计算有 K 个不同质因数的数字
int findSecretNumber(int L, int R, int K) {sieve();  // 初始化最小质因数表for (int num = L; num <= R; ++num) {int n = num;int factorCount = 0;while (n > 1) {int p = smallestPrimeFactor[n];factorCount++;while (n % p == 0) n /= p;}if (factorCount == K) return num;  // 找到符合条件的数}return -1;  // 没有找到
}int main() {int L, R, K;cin >> L >> R >> K;cout << findSecretNumber(L, R, K) << endl;return 0;
}

这个程序使用埃拉托斯特尼筛法预处理最小质因数,然后通过检查每个数的不同质因数数量来找出满足条件的秘密数字。

相关文章:

  • 凡人修仙传8w字大纲pdf
  • 线程池详解并使用Go语言实现 Pool
  • python docx 添加动态表格
  • 从汇编看函数调用
  • 008 CSS盒子模型
  • 如何成为一名嵌入式C语言高手?
  • 突破编程_前端_SVG(概述)
  • 通俗易懂的理解 ADC(2)
  • zabbix绑定钉钉进行通知,网页端添加JavaScript,无脑式操作
  • sharo反序列化漏洞
  • 算法| ss 双指针
  • CentOS7安装Tomcat
  • 如何在plesk面板安装域名付费SSL证书
  • 云原生架构(微服务、容器云、DevOps、不可变基础设施、声明式API、Serverless、Service Mesh)
  • 大语言模型中常见小模型LLM垂直领域应用微调数据集
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • angular2开源库收集
  • co模块的前端实现
  • css布局,左右固定中间自适应实现
  • ES6系统学习----从Apollo Client看解构赋值
  • golang 发送GET和POST示例
  • interface和setter,getter
  • Javascript弹出层-初探
  • js如何打印object对象
  • KMP算法及优化
  • springboot_database项目介绍
  • 翻译--Thinking in React
  • 将回调地狱按在地上摩擦的Promise
  • 爬虫模拟登陆 SegmentFault
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 入门到放弃node系列之Hello Word篇
  • 为视图添加丝滑的水波纹
  • 无服务器化是企业 IT 架构的未来吗?
  • 主流的CSS水平和垂直居中技术大全
  • 整理一些计算机基础知识!
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #162 (Div. 2)
  • #Linux(权限管理)
  • ()、[]、{}、(())、[[]]命令替换
  • (3)(3.5) 遥测无线电区域条例
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (翻译)terry crowley: 写给程序员
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (一)appium-desktop定位元素原理
  • (一)kafka实战——kafka源码编译启动
  • (转)ABI是什么
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]