GENEVE

我还想继续玩c++

导航

OI模板(1)——欧拉筛法(Euler) O(n)

Posted on 2015-08-24 21:12  GENEVE  阅读(318)  评论(0)    收藏  举报

前面就不写分析了,所有的注释均在相应代码附近

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;

typedef long long ll;

const int Size = 2333333;

int n; 
int prime[Size],phi[Size],factor_max[Size];
// prime[0] 目前质数的总个数,prime[i] 第i个质数的值
// phi[i] i的欧拉函数值 欧拉函数:比i小且与i互质的数的个数
// factor_max[i] i的最大质因子,即i由factor_max[i]筛出 

void Euler(void);//通过欧拉筛法求出1~n的phi值,以及筛查1~n中的素数 

int main(){
	scanf("%d",&n);
	Euler();
	// 输出1~n中的素数 
	for (int i = 1;i <= prime[0]; ++i)
	 	printf("%d ",prime[i]);
	puts("");
	
	//输出1~n中各数的欧拉函数值 
	for (int i = 1;i <= n; ++i)
		printf("%d ",phi[i]);
	puts(""); 
	return 0;
}

void Euler(void){
	for (int i = 2;i <= n; ++i){
		//i还没有被之前的数筛出,那么i一定是质数 
		if (factor_max[i] == 0){
			factor_max[i] = i;//质数的最大的质因子是自己 
			prime[++prime[0]] = i;// 添加新的质数 
			phi[i] = i-1; // 欧拉函数的性质,质数的phi为本身的值-1 想想就是这样 
		}
		for (int j = 1;j <= prime[0]; ++j){
			if (prime[j] * i > n)	break;// 超出所求范围,不必再求
			if (i % prime[j] != 0)//prime[j]不是i的因子 
					phi[i * prime[j]] = phi[i] * (prime[j] - 1);//phi为积性函数,拥有其性质 
			else	phi[i * prime[j]] = phi[i] * prime[j];// 理同上,此时prime[j]是i的因子 
			factor_max[i * prime[j]] = prime[j];// 筛出可求出的最小的合数,此处的最小很重要
			if (i % prime[j] == 0)	break; 
		}
	}
	phi[1] = 1;//1 的phi指要自己输入,无法筛出,毕竟前面已经没有其他的数字了 
}