最近打模板,发现自己好像快要忘记欧拉函数怎么搞了,所以写一下备忘
质数筛法
艾氏筛
算法复杂度: $ O(nloglogn)$
算法实现:对于每个质数 $ x$, 标记 $ x imes x, x imes (x+1), cdots, [N / x] imes x$为合数
代码:
inline void era_prime() {
m = 0;
memset(NotPrime, 0, sizeof(NotPrime));
for (int i = 2; i <= n; ++ i) {
if (NotPrime[i]) continue;
prime[++m] = i;
for (int j = i; j <= n/i; ++ j) NotPrime[i * j] = 1;
}
}
欧拉筛
算法复杂度: $ O(n)$
算法实现:保证每个合数只被筛一次
拓展:求欧拉函数,一个数的因子数
代码:
inline void euler_prime() {
m = 0;
memset(NotPrime, 0, sizeof(NotPrime));
for (int i = 2; i <= n; ++ i) {
if (!NotPrime[i]) prime[++m] = i;
for (int j = 1; j <= m && i * prime[j] <= n; ++ j) {
NotPrime[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
}
欧拉函数
定义和相关
参见博客浅谈欧拉函数
基于线性筛的算法
算法实现:基于积性函数的性质
代码:
inline void euler_prime() {
m = 0;
memset(NotPrime, 0, sizeof(NotPrime));
phi[1] = 1;
for (int i = 2; i <= n; ++ i) {
if (!NotPrime[i]) {prime[++m] = i, phi[i] = i - 1;}
for (int j = 1; j <= m && i * prime[j] <= n; ++ j) {
NotPrime[prime[j] * i] = 1;
if (i % prime[j] == 0) {phi[i * prime[j]] = phi[i] * prime[j];break;}
else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
莫比乌斯反演
参见博客莫比乌斯反演
莫比乌斯函数也是积性函数,所以可以用线性筛在(O(n))时间解决
void sieve() {
fill(prime, prime + maxn, 1);
mu[1] = 1, tot = 0;
for (int i = 2; i < maxn; i++) {
if (prime[i]) {
prime[++tot] = i, mu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] < maxn; j++) {
prime[i * prime[j]] = 0;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = -mu[i];
}
}
}
}