欧拉筛
欧拉筛
质数筛
也称线性筛
它比时间复杂度为 \(O(n\log\log n)\) 的埃氏筛更优,因为埃氏筛会有筛重。
欧拉筛保证每个合数只会被它的最小质因数筛掉,所以每个数只会被筛一次。
时间复杂度 \(O(n)\)
#include
#include
std::vector prime;//存放筛出来的质数
std::bitset<100000003> cmpst;//是否是合数(composite)
inline void Euler(register int n) {
cmpst.reset();
for (register int i=2; i<=n; ++i) {
if (!cmpst[i]) prime.push_back(i);//不是合数
for (register int p : prime) {
if (i * p > n) break;
cmpst[i*p] = 1;//标记合数
if (i % p == 0) break;//核心操作:此时p是i的最小质因数
}
}
}
欧拉函数筛
特殊地,对于一个质数 \(p\) ,有 \(\varphi(p)=p-1\)
同时,因为欧拉函数 \(\varphi\) 是积性的,所以有 \(\forall\gcd(a,b)=1,\ \varphi(a\times b)=\varphi(a)\times\varphi(b)\)
又因为对于任意两个质数 \(p_1,p_2\) ,必有 \(\gcd(p_1,p_2)=1\) ,所以我们考虑用质数筛出合数的 \(\varphi\) 值。
时间复杂度 \(O(n)\)
#include
#include
template class Phi {
private:
int n, phi[N];
std::vector prime;
std::bitset cmpst;//composite;
void Euler() {
cmpst.reset();
phi[1] = 1;
for (register int i=2, tmp; i<=n; ++i) {
if (!cmpst[i]) {
prime.push_back(i);
phi[i] = i-1;//质数的phi值
}
for (register int p : prime) {
tmp = i*p;
if (tmp > n) break;
cmpst[tmp] = 1;//标记合数
if (i%p == 0) {//同样的核心操作
phi[tmp] = phi[i] * p;
break;
} phi[tmp] = phi[i] * phi[p];//合数的phi值,利用phi的积性
}
}
}
public:
Phi() : n(N<1?0:N-1) { Euler(); }
Phi(int _n) : n(_n) { Euler(); }
void build(int _n) { n = _n, Euler(); }
int operator () (int x) const { return phi[x]; }
int max_n() const { return n; }
};