欧拉函数&欧拉定理
欧拉定理其实就是这么一句话:
\[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\)了~