1. 程式人生 > 實用技巧 >線性篩質數

線性篩質數

暴力

講解

對於每個數,我們用\(O(\sqrt n)\)的時間判斷是否是質數

所以時間複雜度是\(O(n\sqrt n)\)

程式碼就不給出了

埃式篩法

講解

一個很簡單的篩法

對於每個質數,將它所有的倍數打上標記,表示不是質數

然後就可以做到\(O(nlogn)\)篩質數了

程式碼

bool vis[MAXN];
int prime[MAXN],pn;
void sieve(int x)
{
	for(int i = 2;i <= x;++ i)
	{
		if(!vis[i]) 
		{
			prime[++pn] = i;
			for(int j = i*2;j <= x;j += i)
				vis[j] = 1;
		}
	}
}

歐式篩法

講解

由於埃式篩法每個合數會被所有的質因數篩一遍,所以時間複雜度是\(O(nlogn)\)

但是歐式篩法保證每個合數只會被最小的質因數篩一遍,從而保證了\(O(n)\)的時間複雜度

它是這麼實現的(配程式碼食用更佳):

首先外層迴圈從\(2\)開始列舉倍數\(i\),如果發現當前數字不是質數,加入質數的集合

內層迴圈列舉已經篩出來的質數\(p_j\),將\(i*p_j\)打上標記,如果\(i\)\(p_j\)的倍數,直接跳出迴圈

為什麼可以直接跳出迴圈呢?

\(j'>j\),所以\(p_{j'}>p_j\),因為\(i\)\(p_j\)的倍數,所以\(i*p_{j'}\)

也是\(p_j\)的倍數,它一定會被\(p_j\)篩掉

我們希望每個合數被最小的質因數篩掉,而\(p_j<p_{j'}\),所以可以直接跳出迴圈

程式碼

bool vis[MAXN];
int prime[MAXN],pn;
void sieve(int x)
{
	for(int i = 2;i <= x;++ i)
	{
		if(!vis[i]) prime[++pn] = i;
		for(int j = 1;j <= pn && i * prime[j] <= x;++ j)
		{
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0)//超強優化!
				break;
		}
	}
}