欧拉函数求解(因数分解和线性筛)
C++
欧拉函数及其简略证明
/*
* 欧拉函数
*
* 定义:
* 互质定义:
* 互质是公约数只有1的两个整数,叫做互质整数。公约数只有1的两个自然数,叫做互质自然数。
* 欧拉函数定义:
* 在 1 ~ N 中和 N 互质的数的个数被称为欧拉函数,记作 phi(N)。
*
* 欧拉函数普通解法
* 计算 N 的欧拉函数,使用欧几里得算法查看 1 ~ N 中的数字谁和 N 互质。
*
* 排除法推公式:
* N 质因数分解后可得:
* N = p_1 ^ a_1 * p_2 ^ a_2 * ... * p_k ^ a_k
* 那么利用排除法,1 ~ N 中和 N 互质的数的个数为:
* N - N / p_1 - N / p_2 - ... - N / p_k
* + N / (p_1) ...
* = N * (1 - (1 / p_1) * (1 - (1 / p_2) * ... * (1 - (1 / p_k))
* 同时可以看出,她和我们算数基本定理组成的素数有关,借助素数的递归关系,在线性筛的过程中求解
* 有点向容斥定理那里走
*
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1000010;
int n;
bool st[N];
int phi[N];
long long seive_get_phi(int n) {
phi[1] = 1;
memset(st, false, sizeof st);
vector<int> primes;
for (int i = 2; i <= n; i ++ ) {
if (st[i] == false) {
primes.push_back(i);
phi[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ ) {
st[i * primes[j]] = true;
if (i % primes[j] == 0) { // 注意这里的判断挺有意思
phi[i * primes[j]] = phi[i] * (primes[j]);
break;
} else {
phi[i * primes[j]] = phi[i] * (primes[j] - 1);
}
}
}
long long res = 0;
for (int i = 1; i <= n; i ++ ) {
res += phi[i];
// printf("i=%d, phi=%d\n", i, phi[i]);
}
return res;
}
int get_phi(int x) {
vector<int> primes;
int res = x;
for (int i = 2; i <= x / i; i ++ ) {
if (x % i == 0) {
primes.push_back(i);
while (x % i == 0) {
x /= i;
}
}
}
if (x != 1) {
primes.push_back(x);
}
for (int i = 0; i < primes.size(); i ++ ) {
res = res - res / primes[i]; // res / primes[i] 一定是整数,自己可以证明的
}
return res;
}
int main()
{
scanf("%d", &n);
printf("%lld\n", seive_get_phi(n));
return 0;
}