线性筛:一套框架算法
EP07题:找第10001个素数
估算:开10000 * 20大小的数组,筛选。
素数筛O(loglogN)速度还慢,线性筛O(N)更快
#include <stdio.h>
#define MAX_N 200000
void is_prime(int *arr) {
for (int i = 2; i < MAX_N; i++) {
if (arr[i]) continue;
arr[++arr[0]] = i;
for (int j = i; j < MAX_N / i; j++) {
arr[j * i] = 1;
}
}
return ;
}
int main() {
int arr[MAX_N] = {0};
is_prime(arr);
printf("%d\n", arr[10001]);
return 0;
}
如果一个数字N的素数因式分解中有m种不同的素数,N被标记了m次
而线性筛只被标记1次。速度更快。
标记->数组
线性筛:空间复杂度时间复杂度都为 O(N)
作用:筛选一定范围内所有的素数。
核心思想:用整数 i * prime[j] (小于 i 最小素因数的素数表)去 数组 合数 prime[j] * i。(PS: 素数筛的 i 是素数,这里的 i 是素数+合数)
其中 prime[j] * i 和 i 有如下性质:
prime[j] * i中最小的素数为prime[j]prime[j] * i可以表示成为prime[j] * iprime[j]一定 <=i中最小的素因子- 利用
i * prime[j](所有不大于i中最小素数的集合,如 2,3,5... <=i的最小素数)数组prime[j] * i
判断 i 的最小素数的方法:如果 i % prime[j] == 0,那么 prime[j] 即为 i 的最小素数。
推导:
由 ①② 得:prime[j] * i = prime[j] * ii 是除了 prime[j] * i 以外的最大因数。
③ 保证了 i 是最大因数
如 prime[j] * i = 30:
prime[j] * i = prime[j] (2) * i (15)- 其中
i的最小素因数为 3 (3*5 = 15)
如果 prime[j] = 3,则 i = 10,此时 i 的最小素因数为 2,不满足条件 ③。
④ 表示数组,i 从 2 开始,prime[j] 依次取值 2,3,5... 依次数组 prime[j] * i
例如 数组 prime[j] * i = 30:
- 30 的因子是 2,3,5,6,10,15。
- 当
i = 15时,才会数组prime[j] * i = 30。
随堂练习
被数组的 prime[j] * i = i * prime[j]
prime[j] * i |
i |
prime[j] |
|---|---|---|
| 30 | 15 | 2 |
| 8 | 4 | 2 |
| 45 | 15 | 3 |
i 对应可数组的 prime[j] * i:
i=4,可以数组的prime[j] * i:4×2 = 8i=25,可以数组的prime[j] * i:25×2, 25×3, 25×5i=45,可以数组的prime[j] * i:45×2, 45×3- 能数组 90 的
i等于:45
#include <stdio.h>
#define MAX_N 100
// 素数0 合数1
// 被标记的N = 标记M * P(素数集合)
void linnear_init(int *arr) {
for (int i = 2; i <= MAX_N; i++) {
if (!arr[i]) arr[++arr[0]] = i;
for (int j = 1; j <= arr[0] && arr[j] * i <= MAX_N; j++) {
arr[arr[j] * i] = 1;
if (!(i % arr[j])) break;
}
}
}
void su_prime(int *arr) {
for (int i = 2; i < MAX_N; i++) {
if (!arr[i]) arr[++arr[0]] = i;
for (int j = i; j <= MAX_N / i; j++) {
arr[j * i] = 1;
}
}
return ;
}
int main() {
int arr[MAX_N] = {0};
// su_prime(arr);
xian_init(arr);
for (int i = 1; i <= arr[0]; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
比线性筛更快的判断素数方式:
罗宾米勒测试,有误差(很低),需要数论的知识。
-----------------------------------------------
线性筛提升为算法框架(重要)
求100以内所有数字的因素的个数
F[MAX_N]记录因素个数
先写一个线性筛。 然后改
素数的因子个数肯定为2(1和本身)
F[M] = 2;
M,P互素的话,F(M * P)= F(M) * F(P)
if 互素 F[M * arr[P]] = F[M] * F[arr[P]]
else 不互素(M % arr[p] == 0)
任何的N都可以写成 素因子次幂 连乘 Pi ^ ai
cnt[MAX_N]记录次幂
F[M * arr[P]] = F[M] / (cnt[M] +1) * (cnt[M] + 2)
cnt[M * arr[P]] = cnt[M] +1
作业:求解因子和问题
