/* * 试除法求一个数的欧拉函数(也就是求 [1,n] 内与其互素的数的个数) * 2026-03-13: AC https://codeforces.com/gym/106380/submission/366492238 */ longlongeuler_phi(longlong n){ longlong res = n; // p 从 2 开始,逐个递增,试到 sqrt(n) 为止 for (longlong p = 2; p * p <= n; p++) { // 如果 p 能整除 n,那么 p 一定是质数。 // 为什么?因为如果 p 是合数,比如 p = 6 = 2 × 3, // 那么在 p=2 和 p=3 的时候,n 中的 2 和 3 已经被除干净了, // 此时 n 不可能被 6 整除,所以 n % 6 != 0,这个 if 进不来。 // 因此能进到这个 if 里的 p,一定是质因子。 if (n % p == 0) { // 发现质因子 p,对 res 乘上 (1 - 1/p) 这个因子 // 即 res = res / p * (p - 1) res = res / p * (p - 1); // 把 n 中所有的 p 除干净 // 这样后续更大的 p 的倍数就不可能再整除 n 了 while (n % p == 0) n /= p; } } // 循环结束后,如果 n > 1,说明 n 还剩一个大于 sqrt(原始n) 的质因子 // (一个数最多只有一个大于 sqrt 的质因子) if (n > 1) { res = res / n * (n - 1); } return res; }
这是 Euler 定理(欧拉定理)。
内容很简洁:对于任意正整数 m 和整数 a,若 gcd(a,m)=1,则
aφ(m)≡1(modm)
其中 φ(m) 是欧拉函数,表示 1 到 m 中与 m 互素的正整数个数。
图中的结论就是把 a=10 代入:因为已经去掉了 m 中 2 和 5 的因子,保证了 gcd(10,m)=1,所以直接套用 Euler 定理得到 10φ(m)≡1(modm)。 直觉上为什么成立:考虑模 m 的缩系(即 1 到 m 中所有与 m 互素的数构成的集合 S,共 φ(m) 个元素)。当 gcd(a,m)=1 时,把 S 中每个元素都乘以 a,得到的集合模 m 后恰好还是 S(因为乘以 a 是模 m 缩系上的一个双射)。于是把所有元素的乘积写出来:
x∈S∏(ax)≡x∈S∏x(modm)
左边提出 a:
aφ(m)×x∈S∏x≡x∈S∏x(modm)
因为 ∏x∈Sx 与 m 互素(S 中每个元素都与 m 互素)(说白了,只要是除数和 m 互素,就有逆元,就可以除),可以两边消掉,就得到 aφ(m)≡1(modm)。
它的特殊情况是 Fermat 小定理:当 m=p 为素数时,φ(p)=p−1,即 ap−1≡1(modp)。
呃,首先我们还是一步一步来吧,就是首先,我们可以想到,就是 m 当中的这个因数还是越少越好嘛,想办法先消掉一些。
下面这一步也是比较自然的,因为注意到,0 是永远都在的。
我们可以把这个 m 当中的因数 2,5 给除掉(因为如果原数字不满足,就加 0 即可),得到的新 m 和这个 10 互质(反正应该就是想办法让原数和 10 互质,可以通过不断除以 10,记录一下除 10 的这个个数,最后 +0 即可)。