Fork me on GitHub

欧拉函数

欧拉函数的计算推导

首先,由算术基本定理

\(N = p_1^{a1}p_2^{a2}...p_m^{am}\)

每个因子都不能再分解了,即他们是素数。并且他们和\(N\)是互质的。

那么\(1-N\)之间与\(N\)互质的个数怎么计算呢,根据容斥定理?

  1. 把每个因子 \(p_x\)的倍数全部去掉,因为他的倍数和\(N\)的因子就是他前面乘上的系数。对于每个因子\(p_x\)一共有\(floor {N\over p_x}\)
  2. 因为还有一种可能是每两个因子即\(p_ip_j\)相乘。这样的数字也不是与\(N\)互质的数。但是在第一步的时候已经删去了两次,也就是去多了。所以要加上一次\(floor(N/p_i*p_j)\)
  3. 同理还有可能有三个因子相乘的他们被第一步减去了三次,被第二步加上了三次,所以还要在这里减去一次
  4. 以此类推

最终的结果为

\(\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;
}
posted @ 2020-02-21 15:16  WalterJ726  阅读(223)  评论(0编辑  收藏  举报