1. 程式人生 > 其它 >尤拉篩

尤拉篩

尤拉篩

質數篩

也稱線性篩

它比時間複雜度為 \(O(n\log\log n)\) 的埃氏篩更優,因為埃氏篩會有篩重。

尤拉篩保證每個合數只會被它的最小質因數篩掉,所以每個數只會被篩一次。

時間複雜度 \(O(n)\)

#include <vector>
#include <bitset>
std::vector<int> 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 <vector>
#include <bitset>
template<int N> class Phi {
private:
	int n, phi[N];
	std::vector<int> prime;
	std::bitset<N> 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; }
};

本文來自部落格園,作者:Gyan083,轉載請註明原文連結:https://www.cnblogs.com/gyan083/p/15549884.html