欧拉函数&欧拉定理

欧拉定理其实就是这么一句话:

\[gcd(a,n)=1\to a^{\varphi (n) }\equiv 1\pmod n \]

然后欧拉函数\(\varphi(n)\)表示小于等于\(n\)的数中和\(n\)互质的数的个数
性质:
1.积性函数:
\(gcd(a,b)=1\to \varphi(ab)=\varphi(a)\varphi(b)\)
从这个定义和组合意义上来说,\(\varphi\)这个函数显然是积性的
因为和\(a\cdot b\)互质是和\(a,b\)同时互质的充要条件,稍微思考不难理解
对于积性函数\(f\),总有\(gcd(a,b)=1\to f(ab)=f(a)f(b)\)
这是定义的逆用
2.\(n=\sum\limits_ {d|n}\varphi(d)\)

3.若\(n=p^k\),\(p\)为质数,则\(\varphi(n)=p^k-p^{k-1}\)
如果一个数和n不互质,那么p为两者最大公约数的约数,反之显然。
所以我们只需要找到\(n\)以内有多少个数被\(p\)整除,减一下就有了

单个数的求法:
考虑把p分解质因数,然后用性质三可以知道每个\(\varphi(p^k)\)
根据积性函数的性质,\(\varphi(n)=\varphi(\prod\limits(p_i^{k_i}))=\prod\limits\varphi(p_i^{k_i})\)

蓝书上还有一个公式可以直接用

点击查看代码
int euler_phi(int n) {
  int m = int(sqrt(n + 0.5));
  int ans = n;
  for (int i = 2; i <= m; i++)
    if (n % i == 0) {
      ans = ans / i * (i - 1);
      while (n % i == 0) n /= i;
    }
  if (n > 1) ans = ans / n * (n - 1);
  return ans;
}

如果涉及到一堆数,建议使用线性筛,主要使用性质一:

点击查看代码
// C++ Version
void pre() {
  memset(is_prime, 1, sizeof(is_prime));
  int cnt = 0;
  is_prime[1] = 0;
  phi[1] = 1;
  for (int i = 2; i <= 5000000; i++) {
    if (is_prime[i]) {
      prime[++cnt] = i;
      phi[i] = i - 1;
    }
    for (int j = 1; j <= cnt && i * prime[j] <= 5000000; j++) {
      is_prime[i * prime[j]] = 0;
      if (i % prime[j])
        phi[i * prime[j]] = phi[i] * phi[prime[j]];
      else {
        phi[i * prime[j]] = phi[i] * prime[j];
        break;
      }
    }
  }
}

低于线性的积性函数求法不在\(NOIPtg\)范围以内
但是也不是不学
顺便说一句,见到积性函数求一堆值想线性筛
~~别tmd再拿个埃筛硬干被卡内存痛失\(100pts\)了~

posted @ 2022-08-14 14:29  2K22  阅读(150)  评论(0)    收藏  举报