欧拉函数值的计算一般有两种方法:函数的定义式计算,另一种是使用筛法进行计算
目录
公式计算
欧拉函数的公式:
φ(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;
}