计算欧拉函数

欧拉函数值的计算一般有两种方法:函数的定义式计算,另一种是使用筛法进行计算

目录

公式计算

欧拉函数的公式:

例题:

筛法计算

原理

例题

公式计算

欧拉函数的公式:

φ(n) = n * (1 - 1/p1) * (1 - 1/p2) * … * (1 - 1/pn) 

其中p1,p2...pn是n的所有质因子,其可通过容斥原理来证明,这里不进行证明。

例题:

原题链接(Problem - 602 (nefu.edu.cn)

 ac代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a;
	while (cin >> a) {
		int ans = a;
		for (int i = 2; i * i <= a; i++) {//寻找素因子
			if (a % i == 0) {
				ans = ans / i * (i - 1);//由于使用公式会出现小数,所以对原公式进行变形
				while (a % i == 0) a /= i;
			}
		}
		if (a > 1) ans = ans / a * (a - 1);
		cout << ans << endl;
	}
	return 0;
}

筛法计算

一般用于计算一段区间上所有数字欧拉函数值的和。

原理

其使用的筛法一般是欧拉筛法进行,对于欧拉函数值有四种情况:

1.n==1,这种是最特殊的情况,当n为1时与其互质的数只有1,所以φ(1)=1;

2.在0拉筛中对已筛出的质数的整数倍进行去除时,当所去的数字为已筛出质数的整数倍(i % prime[j] == 0),结论:φ[prime[j] * i] = φ[i] * prime[j];

证明:φ(i) = i * (1 - 1/p1) * (1 - 1/p2) * … * (1 - 1/pk) ;

由于i是prime[j]的倍数,且prime[j]是质数所以φ(prime[j] * i) = (prime[j] * i) * (1 - 1/p1) * (1 - 1/p2) * … * (1 - 1/pk) ;

所以有φ[prime[j] * i] = φ[i] * prime[j];

下面给出一个例子:

因为欧拉函数值中p1,p2...pn与其出现次数无关(至少一次),那么假设i分解质因子后是i=2^100 * 3^100, φ(i) = i * (1 - 1/2) * (1 - 1/3),prime[j] = 3, φ[prime[j] * i] = (prime[j] * i) * (1 - 1/2) * (1 - 1/3)

所以就有φ[prime[j] * i] = prime[j] * i * (1 - 1/2) * (1 - 1/3) = prime[j] * φ(i)

3.当所去的数字不为已筛出质数的整数倍(i % prime[j] != 0),结论:φ[prime[j] * i] = φ[i] * (prime[j] - 1);

证明:(过程与2中证明过程类似)φ(i) = i * (1 - 1/p1) * (1 - 1/p2) * … * (1 - 1/pk) ;

由于i不是prime[j]的倍数,且prime[j]是质数所以φ(prime[j] * i) = (prime[j] * i) * (1 - 1/p1) * (1 - 1/p2) * … * (1 - 1/pk) * (1 - 1/prime[j]) ;

所以有φ[prime[j] * i] = φ[i] * prime[j];

下面给出一个例子:

因为欧拉函数值中p1,p2...pn与其出现次数无关(至少一次),那么假设i分解质因子后是i=2^100 * 3^100, φ(i) = i * (1 - 1/2) * (1 - 1/3),prime[j] = 3, φ[prime[j] * i] = (prime[j] * i) * (1 - 1/2) * (1 - 1/3)

所以就有φ[prime[j] * i] = prime[j] * i * (1 - 1/2) * (1 - 1/3) = prime[j] * φ(i)

4.除去这三中情况以外的情况(所求数字是质数),根据定义除1外都与其互质,所以此时φ(i)= i- 1;

例题 

原题链接:(Problem - 603 (nefu.edu.cn)

ac代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int prime[N], b[N], phi[N];
int cnt;
typedef long long LL;
LL ans;
void init()//欧拉筛法
{
	phi[1] = 1;//第一种情况
	memset(b, 1, sizeof(b));
	b[0] = b[1] = 0;
	for (int i = 2; i < N; i++) {
		if (b[i]) {
			prime[++cnt] = i;
			phi[i] = i - 1;//第四种情况
		}
		for (int j = 1; prime[j] * i < N && j <= cnt; j++) {
			b[prime[j] * i] = 0;
			if (i % prime[j] == 0) {
				phi[prime[j] * i] = phi[i] * prime[j];//第二种情况
				break;
			}
			phi[prime[j] * i] = phi[i] * (prime[j] - 1);//第三种情况
		}
	}
}
int main()
{
	init();
	int n;	
	while (cin >> n) {
		ans = 0;
		for (int i = 1; i <= n; i++) {
			ans += phi[i];
		}
		cout << ans << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值