線性篩法(歐拉篩)

從前有一個素數篩法叫埃拉託斯特尼篩法,它的思想很簡單,把1-n以內素數的整數倍的數字劃掉,留下的就全是素數,但是它的複雜度是O(NlglgN),對於大量不友好數據會跪,於是線性曬登場了。

#include <cstring>
using namespace std;
int prime[1100000],primesize,phi[11000000];
bool isprime[11000000];
void getlist(int listsize)
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=false;
    for(int i=2;i<=listsize;i++)
    {
        if(isprime[i])prime[++primesize]=i;
         for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++)
         {
            isprime[i*prime[j]]=false;
            if(i%prime[j]==0)break;
        }
    }
}

以上就是線性曬代碼,他與埃氏篩法大概有這麼幾點不同:

①:if(i%prime[j]==0)break;

這句代碼保證了每個數最多被篩一次,將時間複雜度降到了線性。

證明如下:prime[]數組中的素數是遞增的,當i能整除prime[j],那麼i*prime[j+1]這個合數肯定被prime[j]乘以某個數篩掉。
   因爲i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那麼i*prime[j+1]=(k*prime[j])*prime
   [j+1]=k’*prime[j],接下去的素數同理。所以不用篩下去了。因此,在滿足i%prime[j]==0這個條件之前以及第一次
   滿足改條件時,prime[j]必定是prime[j]*i的最小因子。


大名鼎鼎的線性曬日常篩素數的速度大概是埃氏篩的3-4倍,然而在小數據中卻有被完爆的可能QAQ

所以歐拉篩法不只是拿來篩個素數,更重要的一點是線性篩可以用來求解積性函數。

積性函數f(x)應滿足f(a×b)=f(a)×f(b),a與b應互素。而完全積性函數則應滿足對於任意的a與b,前面的等式應成立。

先上歐拉phi函數:


memset(check,false,sizeof(check));
fai[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
	if(! check[i])
	{
		prime[tot++] = i;
		fai[i] = i - 1;
	}
	for(int j = 0 ; j < tot ; j++)
	{
		if(i * prime[j] > N) break;
		check[i * prime[j]] = true;
		if(i % prime[j] == 0){
			fai[i * prime[j]] = fai[i] * prime[j];
			break;
		}
		else	{
			fai[i * prime[j]] = fai[i] * (prime[j] - 1);
		}
	}
}
	
再來個線性篩解莫比烏斯函數:

memset(check,false,sizeof(check));
mu[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
	if(! check[i])
	{
		prime[tot++] = i;
		mu[i] = -1;
	}
	for(int j = 0 ; j < tot ; j++)
	{
		if(i * prime[j] > N) break;
		check[i * prime[j]] = true;
		if(i % prime[j] == 0){
			mu[i * prime[j]] = 0;
			break;
		}
		else	{
			mu[i * prime[j]] = -mu[j];
		}
	}
}
	







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章