欧拉函数
欧拉函数
定义法
定义法求欧拉函数是O(sqrt(n))的时间复杂度
只可以求单个数的欧拉函数,
/*
欧拉函数φ的定义, φ(i)表示从[1, i]之间和i互质的数量(a和b互质即gcd(a, b) == 1)
欧拉函数是积性函数, 例如a, b都为质数, 那么φ(a*b) = φ(a) * φ(b), 递推式为φ(a*b) = φ(a)*φ(b)*gcd(a,b) / φ(gcd(a,b)) (证明暂时搁置)
一个数N = p1^b1 * p2^b2 * p3^b3 * ... * pk^bk;(p为质数)
φ(N) = φ(p1^b1) * φ(p2^b2) * φ(p3^b3) * ... * φ(pk^bk);
φ(p^b) = p^b - p^(b-1); [1, p^b]一共有p^b个数, 不和p^b的数有p, 2p, 3p, ... p^(b-1) * p, 总共p^(b-1)个, 剩下的就是满足要求的即 p^b - p^(b-1)
φ(p^b) = p^b * (1 - 1/p);
φ(N) = p1^b1 * (1 - 1/p1) * p1^b1 * (1 - 1/p1) * ... pk^bk * (1 - 1/pk);
φ(N) = (p1^b1 * p1^b1 * ... * pk^bk) * (1 - 1/p1) * (1 - 1/p2) * ... * (1 - 1/pk);
因为N = p1^b1 * p2^b2 * ... * pk^bk;
φ(N) = N * (1 - 1/p1) * (1 - 1/p2) * ... * (1 - 1/pk);
就可以通过分解N的质因数求出来φ(N), 由此也可以看出, 一个数欧拉函数的大小和质数的次幂无关
试除法分解质因数是O(sqrt(n))的, 所以求φ(N)也就是O(sqrt(n))的
具体见代码
*/
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m;
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n;
int res = n;
for (int i = 2; i <= n / i; i ++ )
{
if (n % i == 0)
{
res = res / i * (i - 1); // 相当于res * (1 - 1 / i), 这样是为了防止出现小数, 下取整没了, 最主要的就是这里
while (n % i == 0) n /= i;
}
}
if (n != 1) res = res / n * (n - 1); // 这里不要忘记
cout << res << endl;
}
return 0;
}
一个数欧拉函数的大小和质因数的次幂无关
筛法求欧拉函数
O(n)
/*
线性筛可以求出很多附加的东西
具体会在代码里写注释
*/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1000010;
int n;
int primes[N], cnt;
bool st[N];
int phi[N]; // phi[i] 是i的欧拉函数
LL sum;
int main()
{
cin >> n;
phi[1] = 1; // 1的欧拉函数是1, 需要手动写上
for (int i = 2; i <= n; i ++ )
{
if (st[i] == 0)
{
primes[ ++ cnt] = i;
sum += phi[i] = i - 1; // 首先如果i是质数, 质数和所有数都互质(除了它自己), 那么对于质数i的φ, 就是i - 1
}
for (int j = 1; primes[j] <= n / i; j ++ )
{
st[i * primes[j]] = true;
if (i % primes[j] == 0) // 如果i % pj == 0 那么pj就是i的最小质因数(这点在线性筛里提到过)
{ // 说明i的质因数包括pj, 那么φ(i)里面包括 (1 - 1/pj), 一个数欧拉函数的大小和其质因数的次幂无关, 根据φ(N) = N * (1 - 1/p1) * (1 - 1/p2) * ... * (1 - 1/pk);
sum += phi[i * primes[j]] = phi[i] * primes[j]; // pj * i 比 i 只多了一个pj而且pj还在i的质因数里面, 那么 φ(i*pj)只比φ(i)多一个pj 也就是 φ(i*pj) = φ(i) * pj
break;
}
sum += phi[i * primes[j]] = phi[i] * (primes[j] - 1); // 和上面同理, 但是pj不是i的质因数, 所以φ(i) 不包含 (1 - 1/pj), φ(pj*i)需要加上这个
}
}
cout << sum + 1 << endl;
return 0;
}