#include <iostream>
#include <algorithm>
#include <time.h>
using namespace std;
// 欧拉函数详解:http://t.csdn.cn/mNtSh
// 同余:http://t.csdn.cn/fah3g
// 逆元:https://zhuanlan.zhihu.com/p/449221995
// 两个正整数只有一个公约数1时,它们的关系叫做互质
// 欧拉函数:1 ~ n 中与 n 互质的数的个数
// n的分解质因数为:p1^a1 * p2^a2 * p3^a3 … pk^ak
// 欧拉函数公式(容斥原理):N * (1 - 1/p1) * (1 - 1/p2) * (1 - 1/p3) * …… * (1 - 1/pk)
int phi(int n)
{
int res = n;
// 分解质因数并代入公式
for (int i = 2; i <= n / i; i++)
{
if (n % i == 0)
{
res = (res / i) * (i - 1); // 等价于N * (1 - 1/p1)
while (n % i == 0)
{
n /= i;
}
}
}
if (n > 1)
{
res = (res / n) * (n - 1);
}
return res;
}
const int N = 100010;
int primes[N], cnt;
bool st[N];
int euler[N]; // euler[i] 表示 i 这个数的欧拉函数
// 筛法求欧拉函数(求 1-n 每个数的欧拉函数)
void get_eulers(int n)
{
cnt = 0;
for (int i = 2; i <= n; i++)
{
if (!st[i])
{
primes[cnt++] = i;
euler[i] = i - 1; // 质数的欧拉函数为本身-1
}
for (int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0)
{
// 如果 pj 是 i 的最小质因子,那么 i 和 (pj*i) 的分解质因子是完全相同的(p1、p2 … pk),而 euler[i] 已经知道了
// euler[i] = i * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)
// euler[i*pj] = (i * pj) * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)
// 显然euler[i*pj] = euler[i] * pj
euler[i * primes[j]] = euler[i] * primes[j];
break;
}
else
{
// 如果 i % pj != 0 的话,那么 (pj*i) 的分解质因子比 i 多了个 pj
// euler[i] = i * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)
// euler[i*pj] = (i * pj) * (1 - 1/pj) * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)
// = i * (pj - 1) * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)
// 显然euler[i*pj] = euler[i] * (primes[j] - 1)
euler[i * primes[j]] = euler[i] * (primes[j] - 1);
}
}
}
}
// 欧拉定理:两个互质的数a、n:a^euler[n] % n = 1
欧拉函数和欧拉定理
于 2023-09-18 13:24:32 首次发布