C++算法之旅、08 基础篇 | 质数、约数
质数
在>1的整数中,如果只包含1和本身这两个约数,就被称为质数(素数)
866 试除法判定
\(O(n)\)
bool isprime(int x) {
if (x < 2) return false;
for (int i = 2; i < x; i++)
if (x % i == 0) return false;
return true;
}
约数 d 与 n / d 成对出现,可以枚举较小的那一个 \(O(\sqrt{n})\)
\(d <= n/d \\ d^2 <= n \\ d <= \sqrt{n}\)
难点
- 循环判断条件不要用 sqrt,每次循环都会执行一遍sqrt函数,比较慢
- 循环判断条件不要用 i * i,存在溢出风险(变成负数)
- 一定不会溢出的写法是 i <= n / i
#include <iostream>
using namespace std;
bool isprime(int n) {
if (n < 2) return false;
for (int i = 2; i <= n / i; i++)
if (n % i == 0) return false;
return true;
}
int main() {
int n;
cin >> n;
while (n--) {
int x;
cin >> x;
if (isprime(x))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
867分解质因数
质因数指能整除给定正整数的质数。把一个合数分解成若干个质因数的乘积的形式,即求质因数的过程叫做分解质因数。
相关理论证明可看 数论——质数:分解质因数 - 知乎 (zhihu.com)
从2到\(\sqrt{n}\)枚举n的所有质因数,求其指数并输出。还要考虑最多有一个质因素大于\(\sqrt{n}\)的情况,单独判断输出。 最坏 \(O(\sqrt{n})\),最好 \(O(logn)\) (考虑\(2^k\)情况)
#include <iostream>
using namespace std;
void divide(int n) {
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
int cnt = 0;
while (n % i == 0) {
cnt++;
n /= i;
}
cout << i << " " << cnt << endl;
}
}
if (n > 1) cout << n << " " << 1 << endl;
}
int main() {
int n;
cin >> n;
while (n--) {
int x;
cin >> x;
divide(x);
cout << endl;
}
}
868筛质数
朴素算法是从前往后删倍数(2~p-1都不是n的约数,所以n是质数)
调和级数\(1/2+1/3+1/4+1/5+...+1/∞\) 极限等于 \(lnn+C\)。
\(lnn < log_2n\),因此朴素算法复杂度为 \(O(nlogn)\)
埃式筛法:只删除2~p-1中质数的倍数,原理跟867类似(算数基本定理:每个正整数都可以唯一表示成素数的乘积)
粗略估计:1~n当中,有\(n/lnn\)个质数,时间复杂度变为 \(O(n)\),真实复杂度 \(O(nloglogn)\),两者差不多一个级别
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = n;
for (int j = i + i; j <= n; j += i) st[j] = true;
}
}
}
int main() {
int n;
cin >> n;
get_primes(n);
cout << cnt << endl;
return 0;
}
线性筛法,\(O(n)\),基本思路一样(基于每个质数的倍数为非质数),当 n 很大时,速度比埃式筛法快一倍。
每个数只会被其最小质因子筛掉
- i % pj == 0,pj 一定是 i 的最小质因子,pj 一定是 pj * i 的最小质因子
- i % pj != 0,pj 一定小于 i 的所有质因子,pj 一定是 pj * i 的最小质因子
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j] * i <= n; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break; // primes[j] 一定是 i 的最小质因子
}
}
}
int main() {
int n;
cin >> n;
get_primes(n);
cout << cnt << endl;
return 0;
}
约数
869 试除法求约数
与866优化原理类似 \(O(\sqrt{n})\)
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
vector<int> get_divisors(int n) {
vector<int> res;
for (int i = 1; i <= n / i; i++) {
if (n % i == 0) {
res.push_back(i);
if (i != n / i) res.push_back(n / i); // 避免平方
}
}
sort(res.begin(), res.end());
return res;
}
int main() {
int n;
cin >> n;
while (n--) {
int x;
cin >> x;
auto res = get_divisors(x);
for (auto t : res) cout << t << ' ';
cout << endl;
}
}
870约数个数

利用算术基本定理,每个质因数有(1+n)种选择。m个选择组合得出m个约数
具体原理可看 第四章 数学知识(一)——质数与约数 - 知乎 (zhihu.com)
INT_MAX 约数个数约1500
求 n 个数的乘积的约数个数,可以求每个数的每个质因子指数之和,然后套用公式。
#include <algorithm>
#include <iostream>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main() {
int n;
cin >> n;
unordered_map<int, int> primes;
while (n--) {
int x;
cin >> x;
for (int i = 2; i <= x / i; i++) {
while (x % i == 0) {
x /= i;
primes[i]++;
}
}
if (x > 1) primes[x]++;
}
LL res = 1;
for (auto prime : primes) res = res * (prime.second + 1) % mod;
cout << res << endl;
return 0;
}
871约数之和
#include <algorithm>
#include <iostream>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int main() {
int n;
cin >> n;
unordered_map<int, int> primes;
while (n--) {
int x;
cin >> x;
for (int i = 2; i <= x / i; i++) {
while (x % i == 0) {
x /= i;
primes[i]++;
}
}
if (x > 1) primes[x]++;
}
LL res = 1;
for (auto prime : primes) {
int p = prime.first, a = prime.second;
LL t = 1;
while (a--) {
t = (t * p + 1) % mod;
}
res = res * t % mod;
}
cout << res << endl;
return 0;
}
872最大公约数
欧几里得算法(辗转相除法)

#include <algorithm>
#include <iostream>
#include <unordered_map>
using namespace std;
// a 和 0 的最大公约数是 a
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int main() {
int n;
cin >> n;
while (n--) {
int a, b;
cin >> a >> b;
cout << gcd(a, b) << endl;
}
return 0;
}
C++算法之旅、08 基础篇 | 质数、约数的更多相关文章
- iOS系列 基础篇 08 文本与键盘
iOS系列 基础篇 08 文本与键盘 目录: 1. 扯扯犊子 2. TextField 3. TextView 4. 键盘的打开和关闭 5. 打开/关闭键盘的通知 6. 键盘的种类 7. 最后再扯两句 ...
- 【算法与数据结构】在n个数中取第k大的数(基础篇)
(转载请注明出处:http://blog.csdn.net/buptgshengod) 题目介绍 在n个数中取第k大的数(基础篇),之所以叫基础篇是因为还有很多更高级的算法,这些 ...
- ESP8266开发之旅 基础篇① 走进ESP8266的世界
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇④ ESP8266与EEPROM
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- Java多线程系列--“基础篇”08之 join()
概要 本章,会对Thread中join()方法进行介绍.涉及到的内容包括:1. join()介绍2. join()源码分析(基于JDK1.7.0_40)3. join()示例 转载请注明出处:http ...
- 【SSM之旅】Spring+SpringMVC+MyBatis+Bootstrap整合基础篇(一)项目简介及技术选型相关介绍
试水 一直想去搭建个自己的个人博客,苦于自己的技术有限,然后也个人也比较懒散.想动而不能动,想动而懒得动,就这么一直拖到了现在.总觉得应该把这几年来的所学总结一番,这样才能有所成长. 不知在何时,那就 ...
- 《量化投资:以MATLAB为工具》连载(1)基础篇-N分钟学会MATLAB(上)
http://blog.sina.com.cn/s/blog_4cf8aad30102uylf.html <量化投资:以MATLAB为工具>连载(1)基础篇-N分钟学会MATLAB(上) ...
随机推荐
- 如何洞察 C# 程序的 GDI 句柄泄露
一:背景 1. 讲故事 前段时间有位朋友找到我,说他的程序界面操作起来很慢并且卡顿等一些不正常现象,从任务管理器看了下 GDI句柄 已经到 1w 了,一时也找不出什么代码中哪里有问题,让我帮忙看下,其 ...
- 曲线艺术编程 coding curves 第八章 贝赛尔曲线(Bézier Curves)
贝赛尔曲线(Bézier Curves) 原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(s ...
- Junit执行器Runner探索之旅
单元测试是每个程序员必备的技能,而Runner是每个单元测试类必有属性.本文通过解读Junit源码,介绍junit中每个执行器的使用方法,让读者在单元测试时,可以灵活的使用Runner执行器. 一.背 ...
- 从0搭建Vue3组件库(十):如何搭建一个 Cli 脚手架
本篇文章将实现一个名为create-easyest脚手架的开发,只需一个命令npm init easyest就可以将整个组件库开发框架拉到本地. 创建 Cli 包 首先,我们在 packages 目录 ...
- uniapp微信小程序转支付宝小程序踩坑(持续更新)
首先第一个,真有被折磨到! // 微信正常使用,支付宝不行 <image src="https://static.dabapiao.com/images/coupon-index.pn ...
- 统信UOS系统开发笔记(八):在统信UOS上编译搭建mqtt基础环境(版本使用QMQTT::Clinet)
前言 统信uos使用到mqtt开发,需要重新编译mqtt,本篇描述统信uos20上的mqtt源码编译和环境搭建. 注意 这里下载的mqtt版本与其他几篇文章的不同,这里是使用QMQTT:: ...
- 力扣 (LeetCode)算法入门——Day1
704. 二分查找 题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. ...
- 介绍Vue router的history模式以及如何配置history模式
引言 Vue router给我们提供了两种路由模式,分别是hash模式和history模式.其中默认是使用hash模式,即URL中带有一个#符号,但是处于业务或个人喜爱的差别,Vue router也提 ...
- 配置k8s拉取Harbor镜像
创建Secret # 认证名称为:docker-harbor-registry kubectl create secret docker-registry docker-harbor-registry ...
- Three.js使用InstancedMesh实现性能优化
1. 引言 有这么一种场景:需要渲染一座桥,桥有很多桥柱,桥柱除了位置与倾斜角度不完全相同外,其他均相同,由于桥柱数量很大,使用three.js绘制较为卡顿,如何优化?注意,要求后续能选中某个桥柱 2 ...