欧拉函数
欧拉函数的计算推导
首先,由算术基本定理
\(N = p_1^{a1}p_2^{a2}...p_m^{am}\)
每个因子都不能再分解了,即他们是素数。并且他们和\(N\)是互质的。
那么\(1-N\)之间与\(N\)互质的个数怎么计算呢,根据容斥定理?
- 把每个因子 \(p_x\)的倍数全部去掉,因为他的倍数和\(N\)的因子就是他前面乘上的系数。对于每个因子\(p_x\)一共有\(floor {N\over p_x}\)个
- 因为还有一种可能是每两个因子即\(p_ip_j\)相乘。这样的数字也不是与\(N\)互质的数。但是在第一步的时候已经删去了两次,也就是去多了。所以要加上一次\(floor(N/p_i*p_j)\)
- 同理还有可能有三个因子相乘的他们被第一步减去了三次,被第二步加上了三次,所以还要在这里减去一次
- 以此类推
最终的结果为
\(\phi(N) = N * (1 - {1 \over p_1})* (1 - {1 \over p_2})...* (1 - {1 \over p_m})\)
可以验证一下,\(p_1\)的系数是第一个取一个,其他的全部取1,全部是正数,自己是-1.所以是-1
\(p_1p_2\)第一项取一个,第二项取一个是正数,其他的也是取正数。所以系数是1
时间复杂度
时间复杂度瓶颈在求质因数上面
因为求解质因数那里是\(O(\sqrt{N})\),
但是约数在正整数范围内最多有1500多个,循环也就1500多遍
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int phi(int x)
{
long long res = x;
for (int i = 2; i <= x / i; i++)
{
if (x % i == 0)
{
res = res / i * (i - 1);
while (x % i == 0)
{
x /= i;
}
}
}
if (x > 1)
res = res / x * (x - 1);
// 这里不能写成 res *= x-1/x 会变成0的
// 因为可能会比他小并且还容易爆int
return res;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int x;
cin >> x;
cout << phi(x) << endl;
}
return 0;
}
有什么问题可以加qq:1281372141进行交流