- 闫晟淏 的博客
质数与约数&快速幂总结
- @ 2025-7-24 22:05:44
一、定义
1.约数和倍数的定义:
a能被b整除就说明a是b的约数,b是a的倍数。
2.质数和合数的定义:
质数和合数是大于1的整数,如果只包含1和本身两个约数叫做质数,不然就叫做合数。
二、质数判断方法(时间复杂度的进化)
1.质数的判断方法:
方法一:线性判断质数
枚举2~n-1的所有数字一个个除n,如果都没余数则为质数,不然即是合数。
示例代码
bool is_prime(int n) {
if (n < 2) return 0;
for (int i=2; i<=n-1; i++) {
if (n%i == 0) return 0;
}
return 1;
}
时间复杂度:O(n)
方法二:对半判断质数
根据的性质:若n%i==0那么n%(n/i)==0
由此,我们可以得出要判断质数只要列举较小的数字就行,由此得出代码:
bool is_prime(int n) {
if (n < 2) return 0;
for (int i=2; i<=n/i; i++) { // 写 i<=sqrt(n)也可以,但是还需要算,比较慢。
if (n%i == 0) return 0;
}
return 1;
}
时间复杂度:O(log(n))
由此其得到了进化:由O(n) ————> O(log(n))
质数筛(一个可以快速筛出质数的东西):
在需要多次判断质数时 我们就要使用时间复杂度更低的质数筛了
其分为朴素筛、埃氏筛、欧拉筛(线性筛)三大筛(时间复杂度从高到低)
1.朴素筛
const int N = 1e6+5;
int primes[N], cnt; // primes用来存储质数,cnt是对应数组的下标
bool st[N]; // st[i]标记数字是否被筛掉
void get_primes(int n) {
// 筛选 2~n中的所有质数
for (int i=2; i<=n; i++) {
if (!st[i]) {
primes[++cnt] = i; // 质数存到数组中
}
for (int j=i+i; j<=n; j+=i) st[j] = 1; // 筛掉数字的倍数
}
// 这样过完之后,所有的质数就存到了primes数组中
// 同时 st 中标记了每个数字是否是质数。
}
2.埃氏筛
const int N = 1e6+5;
int primes[N], cnt; // primes用来存储质数,cnt是对应数组的下标
bool st[N]; // st[i]标记数字是否被筛掉
void get_primes(int n) {
// 筛选 2~n中的所有质数
for (int i=2; i<=n; i++) {
if (!st[i]) {
primes[++cnt] = i; // 质数存到数组中
for (int j=i+i; j<=n; j+=i) st[j] = 1; // 筛掉质数的倍数
}
}
// 这样过完之后,所有的质数就存到了primes数组中
// 同时 st 中标记了每个数字是否是质数。
}
3.欧拉筛(线性筛)
void get_primes(int n) {
// 筛选 2~n中的所有质数
for (int i=2; i<=n; i++) {
if (!st[i]) primes[++cnt] = i; // 质数存到数组中
// primes[j] <= n/i 理解为 primes[j]*i <= n,即只筛n范围内的数字
for (int j=1; primes[j]<=n/i; j++) {
st[primes[j]*i] = 1; // 筛掉i的素数倍数
if (i%primes[j] == 0) break; // 线性复杂度的关键
}
}
}
三、枚举约数
方法一:线性枚举
const int N = 1e5+5;
int res[N], cnt;
void get_divisors(int n) {
for (int i=1; i<=n; i++) {
if (n%i == 0) res[++cnt] = i;
}
}
对半枚举
const int N = 1e5+5;
int res[N], cnt;
void get_divisors(int n) {
for (int i=1; i<=n/i; i++) {
if (n%i == 0) {
res[++cnt] = i;
if (i != n/i) res[++cnt] = n/i; // 这个判断是防止加两次 n/i 进去
}
}
sort(res+1, res+1+cnt); // 如果不要求排序,也可以不用。
// 另外,也可以用两个数组,一个存前半部分一个存后半部分,最后合并,比排序更快。
}
快速幂
思想:通过幂次的二进制拆解,将幂次逐步减少,其时间复杂度从普通幂的O(b)降低到O(logb).

THE END