线性筛法求质数分解、欧拉函数

普通筛法的缺点是:对于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;
}
原文地址:https://www.cnblogs.com/weiyinfu/p/6369010.html