线性筛法求质数分解、欧拉函数
普通筛法的缺点是:对于n,它的质因子有p1,p2,p3,那么n会被划掉3次。
线性筛法的核心思想是:对于n,它只被它的最小质因子p1划掉1次。
线性筛法略加变形即可用来求质数分解和欧拉函数。
求质数分解时,一种方案是对于每个数字n,存储它的全部质因子,这样有点浪费空间。
另一种存储方案是,对于每个数字n,只存储它的最小质因子及其幂。至于其它质因子可以向前递推。这种方式节省空间。
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxn = 1000;
bool isPrime[maxn];
int prime[300], psize;//线性筛法必须用数组存储现有质数
int euler[maxn];//每个数字的欧拉函数值
//nex:每个数字的下一跳,mip:每个数字的最小质因子,ci:每个数字最小质因子的幂
int nex[maxn], mip[maxn], ci[maxn];
void init(){
memset(isPrime, 1, sizeof(isPrime));
psize = 0;
for (int i = 2; i < maxn; i++){
if (isPrime[i]){
prime[psize++] = i;
euler[i] = i - 1;
nex[i] = i;
mip[i] = i;
ci[i] = 1;
}
for (int j = 0; j < psize&&prime[j] * i < maxn; j++){
isPrime[i*prime[j]] = false;
mip[i*prime[j]] = prime[j];
if (i%prime[j] == 0){
//说明i中已经包含prime[j]
euler[i*prime[j]] = euler[i] * prime[j];
nex[i*prime[j]] = nex[i];
ci[i*prime[j]] = ci[i] + 1;
break;
}
else{
euler[i*prime[j]] = euler[i] * (prime[j] - 1);
ci[i*prime[j]] = 1;
nex[i*prime[j]] = i;
}
}
}
}
int main(){
init();
for (int i = 2; i < maxn; i++){
printf("%d euler=%d nex=%d ", i, euler[i], nex[i]);
for (int j = i;; j = nex[j]){
printf("%d^%d ", mip[j], ci[j]);
if (mip[j] == nex[j])break;
}
puts("");
}
return 0;
}